سؤال

الهدف هو إنشاء فئة وهمية تتصرف مثل نتائج DB.

لذلك على سبيل المثال، إذا إرجاع استعلام قاعدة البيانات، باستخدام تعبير Dict، {'ab':100, 'cd':200}, ، ثم أود أن أرى:

>>> dummy.ab
100

في البداية اعتقدت ربما يمكنني القيام بذلك بهذه الطريقة:

ks = ['ab', 'cd']
vs = [12, 34]
class C(dict):
    def __init__(self, ks, vs):
        for i, k in enumerate(ks):
            self[k] = vs[i]
            setattr(self, k, property(lambda x: vs[i], self.fn_readyonly))

    def fn_readonly(self, v)
        raise "It is ready only"

if __name__ == "__main__":
    c = C(ks, vs)
    print c.ab

لكن c.ab إرجاع كائن خاصية بدلا من ذلك.

استبدال setattr اصطف مع k = property(lambda x: vs[i]) ليس استخداما على الإطلاق.

إذن ما هي الطريقة الصحيحة لإنشاء خاصية مثيل في وقت التشغيل؟

ملاحظة: أنا على علم بديل قدم في كيف ال __getattribute__ الطريقة المستخدمة؟

هل كانت مفيدة؟

المحلول

أفترض أنني يجب أن أتوسع هذه الإجابة، الآن بعد أن كنت أكبر سنا وأكثر حكمة ومعرفة ما يحدث. أن تأتي متأخرا أفضل من ألا تأتي أبدا.

أنت يمكن إضافة خاصية إلى فئة ديناميكيا. ولكن هذا هو الصيد: عليك إضافة ذلك إلى صف دراسي.

>>> class Foo(object):
...     pass
... 
>>> foo = Foo()
>>> foo.a = 3
>>> Foo.b = property(lambda self: self.a + 1)
>>> foo.b
4

أ property هو في الواقع تنفيذ بسيط لشيء يسمى واصف. وبعد إنه كائن يوفر معالجة مخصصة لسمة معينة، على فئة معينة. وبعد كيندا مثل وسيلة لعامل ضخمة if شجرة من __getattribute__.

عندما أطلب foo.b في المثال أعلاه، يرى بيثون أن b المعرفة على فئة تنفذ بروتوكول واصفعندما يعني فقط أنه كائن مع __get__, __set__, ، أو __delete__ طريقة. يدعي واصف المسؤولية عن التعامل مع هذه السمة، لذلك يطلق الثعبان Foo.b.__get__(foo, Foo), ، يتم تمرير قيمة الإرجاع إليك بقيمة السمة. في حالة ما اذا property, ، كل هذه الأساليب تستدعي فقط fget, fset, ، أو fdel مررت إلى property البناء.

الواصفات هي حقا طريقة بيثون في تعريض السباكة لتنفيذ OO بأكملها. في الواقع، هناك نوع آخر من واصف أكثر شيوعا property.

>>> class Foo(object):
...     def bar(self):
...         pass
... 
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f2a439d5dd0>>
>>> Foo().bar.__get__
<method-wrapper '__get__' of instancemethod object at 0x7f2a43a8a5a0>

الطريقة المتواضعة هي مجرد نوع آخر من واصف. إنه __get__ المسامير على مثيل الدعوة كوسيطة الأولى؛ في الواقع، يفعل هذا:

def __get__(self, instance, owner):
    return functools.partial(self.function, instance)

على أي حال، أظن أن هذا هو السبب في أن الواصفات تعمل فقط على الفصول الدراسية: إنها إضفاء الطابع الرسمي على الأشياء التي تدفق الطبقات في المقام الأول. إنهم حتى الاستثناء للقاعدة: يمكنك تعيين واصفات من الواضح أن الطبقات هي أنفسهم مثيلات typeفي في الواقع، تحاول أن تقرأ Foo.b لا تزال تدعو property.__get__; ؛ إنه مجرد اصطلاح لواصفات لإرجاع أنفسهم عند الوصول إليها كسمات فئة.

أعتقد أنه من الرائع أن يتم التعبير عن جميع نظام OO في بيثون تقريبا في بيثون. :)

أوه، كتبت WEDY بلوق نشر حول الواصفات مرة أخرى إذا كنت مهتما.

نصائح أخرى

الهدف هو إنشاء فئة وهمية تتصرف مثل نتائج DB.

إذن ما تريده هو القاموس حيث يمكنك تهجئة ['b'] كما ab؟

هذا سهل:

class atdict(dict):
    __getattr__= dict.__getitem__
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

يبدو أنك يمكن أن تحل هذه المشكلة أكثر بكثير ببساطة مع namedtuple, ، لأنك تعرف قائمة الحقول بأكملها في وقت مبكر.

from collections import namedtuple

Foo = namedtuple('Foo', ['bar', 'quux'])

foo = Foo(bar=13, quux=74)
print foo.bar, foo.quux

foo2 = Foo()  # error

إذا كنت بحاجة مطلقا إلى كتابة STERTER الخاصة بك، فسيتعين عليك القيام بعلبة المختصر على مستوى الفصل؛ property() لا يعمل على المثيلات.

لا تحتاج إلى استخدام خاصية لذلك. فقط تجاوز __setattr__ لجعلها تقرأ فقط.

class C(object):
    def __init__(self, keys, values):
        for (key, value) in zip(keys, values):
            self.__dict__[key] = value

    def __setattr__(self, name, value):
        raise Exception("It is read only!")

تادا.

>>> c = C('abc', [1,2,3])
>>> c.a
1
>>> c.b
2
>>> c.c
3
>>> c.d
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'd'
>>> c.d = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
Exception: It is read only!
>>> c.a = 'blah'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
Exception: It is read only!

كيفية إضافة الممتلكات إلى فئة بيثون ديناميكيا؟

قل لديك كائن تريد إضافة خاصية إليه. عادة، أريد استخدام الخصائص عندما أحتاج إلى بدء إدارة الوصول إلى سمة في التعليمات البرمجية التي لها استخدام المصب، حتى أتمكن من الحفاظ على واجهة برمجة تطبيقات ثابتة. الآن سأضيفها عادة إلى التعليمات البرمجية المصدر حيث يتم تعريف الكائن، ولكن دعونا نفترض أنك لا تملك هذا الوصول، أو تحتاج إلى اختيار وظائفك حقا بشكل حيوي.

إنشاء فئة

باستخدام مثال بناء على وثائق ل property, ، دعونا إنشاء فئة من الكائنات بسمة "مخفية" وإنشاء مثيل منه:

class C(object):
    '''basic class'''
    _x = None

o = C()

في بيثون، نتوقع أن تكون هناك طريقة واحدة واضحة للقيام بالأشياء. ومع ذلك، في هذه الحالة، سأظل بطريقتين: مع تدوين الديكور، وبدون. أولا، دون تدوين الديكور. قد يكون هذا أكثر فائدة للتخصيص الديناميكي من Getters أو setters أو Deleters.

ديناميكية (ترقيع القرد المعروف أيضا باسم)

دعنا نخلق بعض لفصولنا:

def getx(self):
    return self._x

def setx(self, value):
    self._x = value

def delx(self):
    del self._x

والآن نحن نخصص هذه العقار. لاحظ أننا يمكن أن نختار وظائفنا برمجيا هنا، والرد على السؤال الديناميكي:

C.x = property(getx, setx, delx, "I'm the 'x' property.")

والاستخدام:

>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None
>>> help(C.x)
Help on property:

    I'm the 'x' property.

ديكور

يمكننا أن نفعل نفس الشيء كما فعلنا أعلاه مع تدوين الديكور، ولكن في هذه الحالة، نحن يجب قم بتسمية الطرقات نفس الاسم (وأوصي بحفظها بنفس السمة)، لذا فإن المهمة البرنامجية ليست تافهة للغاية لأنها تستخدم الطريقة المذكورة أعلاه:

@property
def x(self):
    '''I'm the 'x' property.'''
    return self._x

@x.setter
def x(self, value):
    self._x = value

@x.deleter
def x(self):
    del self._x

وتعيين كائن العقار مع STELTISS المنصوص عليها والحذف إلى الفصل:

C.x = x

والاستخدام:

>>> help(C.x)
Help on property:

    I'm the 'x' property.

>>> o.x
>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None

سألت سؤالا مشاجئا في هذا المكدس تجاوز الفضاء لإنشاء مصنع فئة خلق أنواعا بسيطة. النتيجة كانت هذه الإجابة التي لديها نسخة عمل من مصنع الطبقة. هنا مقتطف من الجواب:

def Struct(*args, **kwargs):
    def init(self, *iargs, **ikwargs):
        for k,v in kwargs.items():
            setattr(self, k, v)
        for i in range(len(iargs)):
            setattr(self, args[i], iargs[i])
        for k,v in ikwargs.items():
            setattr(self, k, v)

    name = kwargs.pop("name", "MyStruct")
    kwargs.update(dict((k, None) for k in args))
    return type(name, (object,), {'__init__': init, '__slots__': kwargs.keys()})

>>> Person = Struct('fname', 'age')
>>> person1 = Person('Kevin', 25)
>>> person2 = Person(age=42, fname='Terry')
>>> person1.age += 10
>>> person2.age -= 10
>>> person1.fname, person1.age, person2.fname, person2.age
('Kevin', 35, 'Terry', 32)
>>>

يمكنك استخدام بعض الاختلاف في هذا لإنشاء القيم الافتراضية التي هي هدفك (هناك أيضا إجابة في هذا السؤال الذي يتناول هذا).

لا يمكنك إضافة جديد property() إلى مثيل في وقت التشغيل، لأن الخصائص توجد بيانات البيانات. بدلا من ذلك، يجب عليك إنشاء فئة جديدة ديناميكيا، أو التحميل الزائد __getattribute__ من أجل معالجة واصفات البيانات على المثيلات.

لست متأكدا مما إذا كنت أفهم السؤال تماما، ولكن يمكنك تعديل خصائص المثيل في وقت التشغيل مع المدمج __dict__ من صفك:

class C(object):
    def __init__(self, ks, vs):
        self.__dict__ = dict(zip(ks, vs))


if __name__ == "__main__":
    ks = ['ab', 'cd']
    vs = [12, 34]
    c = C(ks, vs)
    print(c.ab) # 12

بالنسبة لأولئك الذين يأتون من محركات البحث، إليك الأمران الذي كنت أبحث عنه عند الحديث عنه متحرك الخصائص:

class Foo:
    def __init__(self):
        # we can dynamically have access to the properties dict using __dict__
        self.__dict__['foo'] = 'bar'

assert Foo().foo == 'bar'


# or we can use __getattr__ and __setattr__ to execute code on set/get
class Bar:
    def __init__(self):
        self._data = {}
    def __getattr__(self, key):
        return self._data[key]
    def __setattr__(self, key, value):
        self._data[key] = value

bar = Bar()
bar.foo = 'bar'
assert bar.foo == 'bar'

__dict__ جيد إذا كنت ترغب في وضع خصائص تم إنشاؤها ديناميكيا. __getattr__ من الجيد أن تفعل شيئا فقط عند حاجة القيمة، مثل الاستعلام قاعدة بيانات. المجموعة / احصل على التحرير والسرد مناسب لتبسيط الوصول إلى البيانات المخزنة في الفصل (مثل في المثال أعلاه).

إذا كنت ترغب فقط في ملكية ديناميكية واحدة، إلقاء نظرة على خاصية() وظيفة مدمجة.

أفضل طريقة لتحقيقها هي تحديد __slots__. وبعد وبهذه الطريقة لا يمكن أن تحتوي حالاتك على سمات جديدة.

ks = ['ab', 'cd']
vs = [12, 34]

class C(dict):
    __slots__ = []
    def __init__(self, ks, vs): self.update(zip(ks, vs))
    def __getattr__(self, key): return self[key]

if __name__ == "__main__":
    c = C(ks, vs)
    print c.ab

هذا يطبع 12

    c.ab = 33

ذلك يعطي: AttributeError: 'C' object has no attribute 'ab'

مجرد مثال آخر كيفية تحقيق التأثير المرغوب فيه

class Foo(object):

    _bar = None

    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, value):
        self._bar = value

    def __init__(self, dyn_property_name):
        setattr(Foo, dyn_property_name, Foo.bar)

حتى الآن يمكننا أن نفعل أشياء مثل:

>>> foo = Foo('baz')
>>> foo.baz = 5
>>> foo.bar
5
>>> foo.baz
5

يمكنك استخدام التعليمات البرمجية التالية لتحديث سمات الفصل باستخدام كائن قاموس:

class ExampleClass():
    def __init__(self, argv):
        for key, val in argv.items():
            self.__dict__[key] = val

if __name__ == '__main__':
    argv = {'intro': 'Hello World!'}
    instance = ExampleClass(argv)
    print instance.intro

يبدو أن هذا يعمل (ولكن انظر أدناه):

class data(dict,object):
    def __init__(self,*args,**argd):
        dict.__init__(self,*args,**argd)
        self.__dict__.update(self)
    def __setattr__(self,name,value):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be set"%(name,self.__class__.__name__)
    def __delattr__(self,name):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be deleted"%(name,self.__class__.__name__)

إذا كنت بحاجة إلى سلوك أكثر تعقيدا، فلا تتردد في تحرير إجابتك.

تعديل

ربما يكون ما يلي أكثر كفاءة في الذاكرة لمجموعات البيانات الكبيرة:

class data(dict,object):
    def __init__(self,*args,**argd):
        dict.__init__(self,*args,**argd)
    def __getattr__(self,name):
        return self[name]
    def __setattr__(self,name,value):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be set"%(name,self.__class__.__name__)
    def __delattr__(self,name):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be deleted"%(name,self.__class__.__name__)

للإجابة على التوجه الرئيسي لسؤالك، تريد سمة للقراءة فقط من DICT من DataSource غير قابل للتغيير:

الهدف هو إنشاء فئة وهمية تتصرف مثل نتائج DB.

لذلك على سبيل المثال، إذا إرجاع استعلام قاعدة البيانات، باستخدام تعبير Dict، {'ab':100, 'cd':200}, ، ثم أود أن أرى

>>> dummy.ab
100

سوف أظهر كيفية استخدام namedtuple من collections الوحدة النمطية لإنجاز هذا فقط:

import collections

data = {'ab':100, 'cd':200}

def maketuple(d):
    '''given a dict, return a namedtuple'''
    Tup = collections.namedtuple('TupName', d.keys()) # iterkeys in Python2
    return Tup(**d)

dummy = maketuple(data)
dummy.ab

عائدات 100

class atdict(dict):
  def __init__(self, value, **kwargs):
    super().__init__(**kwargs)
    self.__dict = value

  def __getattr__(self, name):
    for key in self.__dict:
      if type(self.__dict[key]) is list:
        for idx, item in enumerate(self.__dict[key]):
          if type(item) is dict:
            self.__dict[key][idx] = atdict(item)
      if type(self.__dict[key]) is dict:
        self.__dict[key] = atdict(self.__dict[key])
    return self.__dict[name]



d1 = atdict({'a' : {'b': [{'c': 1}, 2]}})

print(d1.a.b[0].c)

والإخراج هو:

>> 1

توسيع الفكرة من kjfletch.

# This is my humble contribution, extending the idea to serialize
# data from and to tuples, comparison operations and allowing functions
# as default values.

def Struct(*args, **kwargs):
    FUNCTIONS = (types.BuiltinFunctionType, types.BuiltinMethodType, \
                 types.FunctionType, types.MethodType)
    def init(self, *iargs, **ikwargs):
        """Asume that unamed args are placed in the same order than
        astuple() yields (currently alphabetic order)
        """
        kw = list(self.__slots__)

        # set the unnamed args
        for i in range(len(iargs)):
            k = kw.pop(0)
            setattr(self, k, iargs[i])

        # set the named args
        for k, v in ikwargs.items():
            setattr(self, k, v)
            kw.remove(k)

        # set default values
        for k in kw:
            v = kwargs[k]
            if isinstance(v, FUNCTIONS):
                v = v()
            setattr(self, k, v)

    def astuple(self):
        return tuple([getattr(self, k) for k in self.__slots__])

    def __str__(self):
        data = ['{}={}'.format(k, getattr(self, k)) for k in self.__slots__]
        return '<{}: {}>'.format(self.__class__.__name__, ', '.join(data))

    def __repr__(self):
        return str(self)

    def __eq__(self, other):
        return self.astuple() == other.astuple()

    name = kwargs.pop("__name__", "MyStruct")
    slots = list(args)
    slots.extend(kwargs.keys())
    # set non-specific default values to None
    kwargs.update(dict((k, None) for k in args))

    return type(name, (object,), {
        '__init__': init,
        '__slots__': tuple(slots),
        'astuple': astuple,
        '__str__': __str__,
        '__repr__': __repr__,
        '__eq__': __eq__,
    })


Event = Struct('user', 'cmd', \
               'arg1', 'arg2',  \
               date=time.time, \
               __name__='Event')

aa = Event('pepe', 77)
print(aa)
raw = aa.astuple()

bb = Event(*raw)
print(bb)

if aa == bb:
    print('Are equals')

cc = Event(cmd='foo')
print(cc)

انتاج:

<Event: user=pepe, cmd=77, arg1=None, arg2=None, date=1550051398.3651814>
<Event: user=pepe, cmd=77, arg1=None, arg2=None, date=1550051398.3651814>
Are equals
<Event: user=None, cmd=foo, arg1=None, arg2=None, date=1550051403.7938335>

على الرغم من أن العديد من الإجابات مقدمة، إلا أنني لم أجد واحدة سعيدة. لقد اكتشفت الحل الخاص بي الذي يجعل property العمل للحالة الديناميكية. المصدر للإجابة على السؤال الأصلي:

#!/usr/local/bin/python3

INITS = { 'ab': 100, 'cd': 200 }

class DP(dict):
  def __init__(self):
    super().__init__()
    for k,v in INITS.items():
        self[k] = v 

def _dict_set(dp, key, value):
  dp[key] = value

for item in INITS.keys():
  setattr(
    DP,
    item,
    lambda key: property(
      lambda self: self[key], lambda self, value: _dict_set(self, key, value)
    )(item)
  )

a = DP()
print(a)  # {'ab': 100, 'cd': 200}
a.ab = 'ab100'
a.cd = False
print(a.ab, a.cd) # ab100 False

شيء يعمل بالنسبة لي هو:

class C:
    def __init__(self):
        self._x=None

    def g(self):
        return self._x

    def s(self, x):
        self._x = x

    def d(self):
        del self._x

    def s2(self,x):
        self._x=x+x

    x=property(g,s,d)


c = C()
c.x="a"
print(c.x)

C.x=property(C.g, C.s2)
C.x=C.x.deleter(C.d)
c2 = C()
c2.x="a"
print(c2.x)

انتاج |

a
aa

هذا يختلف قليلا عن ما يريد المرجع، لكنني هزت ذهني حتى حصلت على حل عمل، لذلك أنا أضع هنا للرجل / غال المقبلة

كنت بحاجة إلى وسيلة لتحديد العتاق الديناميكي والآجيلة.

class X:
    def __init__(self, a=0, b=0, c=0):
        self.a = a
        self.b = b
        self.c = c

    @classmethod
    def _make_properties(cls, field_name, inc):
        _inc = inc

        def _get_properties(self):
            if not hasattr(self, '_%s_inc' % field_name):
                setattr(self, '_%s_inc' % field_name, _inc)
                inc = _inc
            else:
                inc = getattr(self, '_%s_inc' % field_name)

            return getattr(self, field_name) + inc

        def _set_properties(self, value):
            setattr(self, '_%s_inc' % field_name, value)

        return property(_get_properties, _set_properties)

أعرف مجالاتي في وقت مبكر لذلك أنا ذاهب لإنشاء خصائص بلدي. ملاحظة: لا يمكنك القيام بذلك لكل مثيل، وسوف توجد هذه الخصائص في الفصل !!!

for inc, field in enumerate(['a', 'b', 'c']):
    setattr(X, '%s_summed' % field, X._make_properties(field, inc))

دعنا نختبر كل شيء الآن ..

x = X()
assert x.a == 0
assert x.b == 0
assert x.c == 0

assert x.a_summed == 0  # enumerate() set inc to 0 + 0 = 0
assert x.b_summed == 1  # enumerate() set inc to 1 + 0 = 1
assert x.c_summed == 2  # enumerate() set inc to 2 + 0 = 2

# we set the variables to something
x.a = 1
x.b = 2
x.c = 3

assert x.a_summed == 1  # enumerate() set inc to 0 + 1 = 1
assert x.b_summed == 3  # enumerate() set inc to 1 + 2 = 3
assert x.c_summed == 5  # enumerate() set inc to 2 + 3 = 5

# we're changing the inc now
x.a_summed = 1 
x.b_summed = 3 
x.c_summed = 5

assert x.a_summed == 2  # we set inc to 1 + the property was 1 = 2
assert x.b_summed == 5  # we set inc to 3 + the property was 2 = 5
assert x.c_summed == 8  # we set inc to 5 + the property was 3 = 8

هل هو مربك؟ نعم، آسف لم أستطع التوصل إلى أي أمثلة عالمية حقيقية ذات مغزى. أيضا، هذا ليس للنظرة القلب القلب.

الطريقة الوحيدة لإرفاق الخاصية ديناميكيا هي إنشاء فئة جديدة ومثيل لها مع الخاصية الجديدة.

class Holder: p = property(lambda x: vs[i], self.fn_readonly)
setattr(self, k, Holder().p)

ركضت مؤخرا مشكلة مماثلة، الحل الذي توصلت إليه باستخدام الاستخدامات __getattr__ و __setattr__ بالنسبة للخصائص التي أريدها التعامل معها، يتم تمرير كل شيء آخر إلى النسخ الأصلية.

class C(object):
    def __init__(self, properties):
        self.existing = "Still Here"
        self.properties = properties

    def __getattr__(self, name):
        if "properties" in self.__dict__ and name in self.properties:
            return self.properties[name] # Or call a function, etc
        return self.__dict__[name]

    def __setattr__(self, name, value):
        if "properties" in self.__dict__ and name in self.properties:
            self.properties[name] = value
        else:
            self.__dict__[name] = value

if __name__ == "__main__":
    my_properties = {'a':1, 'b':2, 'c':3}
    c = C(my_properties)
    assert c.a == 1
    assert c.existing == "Still Here"
    c.b = 10
    assert c.properties['b'] == 10

الكثير من الإجابات الموردة تتطلب الكثير من الخطوط لكل خاصية، أي / و / أو - ما كنت أفكر في التنفيذ القبيح أو الشامل بسبب التكرار اللازم لخصائص متعددة، وما إلى ذلك. أفضل الحفاظ على الأشياء الغليان / تبسيطها حتى لا يمكن المبسط بعد الآن أو حتى لا يخدم الكثير من الغرض للقيام بذلك.

باختصار: في الأعمال المكتملة، إذا كررت سطرين من التعليمات البرمجية، فأنا عادة تحويلها في وظيفة مساعد سطر واحد، وهكذا أقوم بتبسيط الرياضيات أو الحجج الفردية مثل (start_x، start_y، end_x، end_y) (X، Y، W، H) IE X، Y، X + W، Y + H (في بعض الأحيان تتطلب MIN / MAX أو إذا كانت W / H سلبية ولا يعجبها التنفيذ، سأطرح من X / Y و ABS W / H. إلخ.).

تجاوز The Interious Getters / Setters طريقة موافق للذهاب، ولكن المشكلة تحتاج إلى القيام بذلك مقابل كل فئة، أو الوالد الفئة إلى تلك القاعدة ... هذا لا يعمل بالنسبة لي كما أفضل أن أكون حرية اختيار الأطفال / الآباء والأمهات للميراث، العقد الطفل، إلخ.

لقد قمت بإنشاء حل يجيب على السؤال دون استخدام نوع بيانات DICT لتزويد البيانات لأنني أجد أن تكون مملة لإدخال البيانات، إلخ ...

يتطلب منك الحل الخاص بي إضافة خطين إضافي فوق صفك لإنشاء فئة أساسية للفئة التي تريد إضافتها من الخصائص إليها، ثم سطر واحد لكل ولديك خيار لإضافة عمليات الاتصال للتحكم في البيانات، وإبلاغك عند تغيير البيانات ، تقييد البيانات التي يمكن تعيينها بناء على القيمة و / أو نوع البيانات، وأكثر من ذلك بكثير.

لديك أيضا خيار استخدام _Object.x، _Object.x = القيمة، _Object.getX ()، _OBJECT.SETX (القيمة) ويتم التعامل معها بشكل مساوي.

بالإضافة إلى ذلك، فإن القيم هي البيانات غير الثابتة الوحيدة التي يتم تعيينها إلى مثيل الفصل، ولكن يتم تعيين الخاصية الفعلية للفئة مما يعني أن الأشياء التي لا تريد تكرارها، لا تحتاج إلى تكرار ... أنت يمكن تعيين قيمة افتراضية حتى لا يحتاج Getter إلى ذلك في كل مرة، على الرغم من وجود خيار لتجاوز القيمة الافتراضية الافتراضية، وهناك خيار آخر حتى يقوم Getter بإرجاع القيمة المخزنة الخام عن طريق تجاوز الإرجاع الافتراضي (ملاحظة: هذه الطريقة يعني أن القيمة الخام تم تعيينها فقط عند تعيين قيمة، وإلا فإنها ليست كذلك - عند إعادة تعيين القيمة، فإنه يعين بلا شيء، إلخ.)

هناك العديد من الوظائف المساعدة أيضا - تتميز الممتلكات الأولى التي تضيفها 2 أو نحو ذلك المساعدين على الفصل للإشارة إلى قيم المثيل ... إنها Resetactacesors (_KEY، ..) Varargs المتكرر (يمكن تكرار كل شيء باستخدام أول Args ) و SetAccessors (_KEY، _Value) مع خيار أكثر إضافته إلى الطبقة الرئيسية إلى المساعد في الكفاءة - تلك المخطط لها هي: طريقة لمجموعة الملاءمة معا، لذلك إذا كنت تميل إلى إعادة تعيين عدد قليل في كل مرة، في كل مرة ، يمكنك تعيينها إلى مجموعة وإعادة تعيين المجموعة بدلا من تكرار المفاتيح المسماة في كل مرة، وأكثر من ذلك.

يتم تخزين القيمة / القيمة المخزنة الخام في صف دراسي., ، __class. يشير إلى فئة Accessor التي تحتوي على Vars / قيم / وقيم ثابتة للممتلكات. _صف دراسي. هو الخاصية نفسها تسمى عند الوصول إليها عبر فئة المثيل أثناء الإعداد / الحصول عليها، إلخ.

يشير الملحق _class .__ إلى الفصل، ولكن لأنه داخلي، يجب تعيينه في الفصل الذي هو السبب في أنني اختارت استخدام __name = accessorfunc (...) لتعيينها، سطر واحد لكل خاصية مع العديد من الاختياري حجج استخدام (باستخدام Varargs المفتاح لأنها أسهل وأكثر كفاءة لتحديد وصيانة) ...

أنا أيضا إنشاء الكثير من الوظائف، كما ذكر، بعضها يستخدم معلومات وظيفة الملحقات حتى لا يتم استدعاؤها (لأنها غير مريحة بعض الشيء في الوقت الحالي - الآن تحتاج إلى استخدام _class..wunkname (_class_instance، Args) - لقد حصلت حول استخدام المكدس / التتبع للاستيلاء على المرجع المثيل للاستيلاء على القيمة من خلال إضافة الوظائف التي تقوم بتشغيل Marathon هذا البت، أو عن طريق إضافة الملاءمة إلى الكائن واستخدام الذات (اسمه للإشارة إلى أنهم للمثيلات والاحتفاظ بالوصول إلى الذات، مرجع فئة AccessorFunc، وغيرها من المعلومات من ضمن تعريفات الوظيفة).

لا يتم القيام به تماما، لكنه عقد فخير. ملاحظة: إذا لم تستخدم __name = AccessorFunc (...) لإنشاء الخصائص، فلن تتمكن من الوصول إلى مفتاح __ على الرغم من أنني أعرفه ضمن دالة Init. إذا قمت بذلك، فلا توجد مشاكل.

أيضا: لاحظ أن الاسم والمفتاح مختلف ... الاسم هو "رسمي"، يستخدم في إنشاء اسم الوظيفة، والمفتاح هو لتخزين البيانات والوصول إليها. أي _class.x حيث هو مفتاح X صغير، سيكون الاسم كبيرا x بحيث تكون getx () هي الوظيفة بدلا من getx () والتي تبدو غريبة بعض الشيء. هذا يسمح ل Self.X بالعمل والبدء مناسبا، ولكن أيضا السماح Getx () وتبدو مناسبة.

لدي مثال على فئة إعداد مع مفتاح / الاسم متطابق، ومختلف إظهاره. تم إنشاء الكثير من وظائف المساعد من أجل إخراج البيانات (ملاحظة: ليس كل هذا مكتمل) حتى تتمكن من رؤية ما يجري.

القائمة الحالية للوظائف باستخدام المفتاح: X، الاسم: X مخرجات AS:

هذا ليس بأي حال من الأحوال قائمة شاملة - هناك عدد قليل منهم لم يتلقوا ذلك في وقت النشر ...

_instance.SetAccessors( _key, _value [ , _key, _value ] .. )                   Instance Class Helper Function: Allows assigning many keys / values on a single line - useful for initial setup, or to minimize lines.    In short: Calls this.Set<Name>( _value ) for each _key / _value pairing.
_instance.ResetAccessors( _key [ , _key ] .. )                                 Instance Class Helper Function: Allows resetting many key stored values to None on a single line.                                           In short: Calls this.Reset<Name>() for each name provided.


Note: Functions below may list self.Get / Set / Name( _args ) - self is meant as the class instance reference in the cases below - coded as this in AccessorFuncBase Class.

this.GetX( _default_override = None, _ignore_defaults = False )                 GET:            Returns    IF ISSET: STORED_VALUE .. IF IGNORE_DEFAULTS: None  .. IF PROVIDED: DEFAULT_OVERRIDE ELSE: DEFAULT_VALUE       100
this.GetXRaw( )                                                                 RAW:            Returns    STORED_VALUE                                                                                                     100
this.IsXSet( )                                                                  ISSET:          Returns    ( STORED_VALUE != None )                                                                                         True

this.GetXToString( )                                                            GETSTR:         Returns    str( GET )                                                                                                       100
this.GetXLen( _default_override = None, _ignore_defaults = False )              LEN:            Returns    len( GET )                                                                                                       3
this.GetXLenToString( _default_override = None, _ignore_defaults = False )      LENSTR:         Returns    str( len( GET ) )                                                                                                3
this.GetXDefaultValue( )                                                        DEFAULT:        Returns    DEFAULT_VALUE                                                                                                    1111

this.GetXAccessor( )                                                            ACCESSOR:       Returns    ACCESSOR_REF ( self.__<key> )                                                                                    [ AccessorFuncBase ] Key: x : Class ID: 2231452344344 : self ID: 2231448283848        Default: 1111       Allowed Types: {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"}     Allowed Values: None
this.GetXAllowedTypes( )                                                        ALLOWED_TYPES:  Returns    Allowed Data-Types                                                                                               {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"}
this.GetXAllowedValues( )                                                       ALLOWED_VALUES: Returns    Allowed Values                                                                                                   None

this.GetXHelpers( )                                                             HELPERS:        Returns    Helper Functions String List - ie what you're reading now...                                                     THESE ROWS OF TEXT
this.GetXKeyOutput( )                                                           Returns information about this Name / Key                                                                                                   ROWS OF TEXT
this.GetXGetterOutput( )                                                        Returns information about this Name / Key                                                                                                   ROWS OF TEXT

this.SetX( _value )                                                             SET:            STORED_VALUE Setter - ie Redirect to __<Key>.Set                                                                            N / A
this.ResetX( )                                                                  RESET:          Resets STORED_VALUE to None                                                                                                 N / A

this.HasXGetterPrefix( )                                                        Returns Whether or Not this key has a Getter Prefix...                                                                                      True
this.GetXGetterPrefix( )                                                        Returns Getter Prefix...                                                                                                                    Get

this.GetXName( )                                                                Returns Accessor Name - Typically Formal / Title-Case                                                                                       X
this.GetXKey( )                                                                 Returns Accessor Property Key - Typically Lower-Case                                                                                        x
this.GetXAccessorKey( )                                                         Returns Accessor Key - This is to access internal functions, and static data...                                                             __x
this.GetXDataKey( )                                                             Returns Accessor Data-Storage Key - This is the location where the class instance value is stored..                                         _x

بعض البيانات التي يتم إخراجها هي:

هذا للحصول على فئة جديدة تم إنشاؤها باستخدام فئة العرض التوضيحي دون أي بيانات تم تعيينها بخلاف الاسم (لذلك يمكن أن يكون الإخراج) وهو _foo، اسم المتغير الذي استخدمته ...

_foo         --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016

    Key       Getter Value        | Raw Key   Raw / Stored Value       | Get Default Value             Default Value            | Get Allowed Types             Allowed Types                                                              | Get Allowed Values            Allowed Values                                                                                                                                                                                                                   |

    Name:     _foo                | _Name:    _foo                     | __Name.DefaultValue( ):       AccessorFuncDemoClass    | __Name.GetAllowedTypes( )     <class 'str'>                                                              | __Name.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    x:        1111                | _x:       None                     | __x.DefaultValue( ):          1111                     | __x.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __x.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    y:        2222                | _y:       None                     | __y.DefaultValue( ):          2222                     | __y.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __y.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    z:        3333                | _z:       None                     | __z.DefaultValue( ):          3333                     | __z.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __z.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Blah:     <class 'int'>       | _Blah:    None                     | __Blah.DefaultValue( ):       <class 'int'>            | __Blah.GetAllowedTypes( )     <class 'str'>                                                              | __Blah.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Width:    1                   | _Width:   None                     | __Width.DefaultValue( ):      1                        | __Width.GetAllowedTypes( )    (<class 'int'>, <class 'bool'>)                                            | __Width.GetAllowedValues( )   Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Height:   0                   | _Height:  None                     | __Height.DefaultValue( ):     0                        | __Height.GetAllowedTypes( )   <class 'int'>                                                              | __Height.GetAllowedValues( )  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |
    Depth:    2                   | _Depth:   None                     | __Depth.DefaultValue( ):      2                        | __Depth.GetAllowedTypes( )    Saved Value Restricted to Authorized Values ONLY                           | __Depth.GetAllowedValues( )   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |


this.IsNameSet( ):    True      this.GetName( ):     _foo                     this.GetNameRaw( ):    _foo                     this.GetNameDefaultValue( ):    AccessorFuncDemoClass    this.GetNameLen( ):    4    this.HasNameGetterPrefix( ):    <class 'str'>                                this.GetNameGetterPrefix( ):    None
this.IsXSet( ):       False     this.GetX( ):        1111                     this.GetXRaw( ):       None                     this.GetXDefaultValue( ):       1111                     this.GetXLen( ):       4    this.HasXGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetXGetterPrefix( ):       None
this.IsYSet( ):       False     this.GetY( ):        2222                     this.GetYRaw( ):       None                     this.GetYDefaultValue( ):       2222                     this.GetYLen( ):       4    this.HasYGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetYGetterPrefix( ):       None
this.IsZSet( ):       False     this.GetZ( ):        3333                     this.GetZRaw( ):       None                     this.GetZDefaultValue( ):       3333                     this.GetZLen( ):       4    this.HasZGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetZGetterPrefix( ):       None
this.IsBlahSet( ):    False     this.GetBlah( ):     <class 'int'>            this.GetBlahRaw( ):    None                     this.GetBlahDefaultValue( ):    <class 'int'>            this.GetBlahLen( ):    13   this.HasBlahGetterPrefix( ):    <class 'str'>                                this.GetBlahGetterPrefix( ):    None
this.IsWidthSet( ):   False     this.GetWidth( ):    1                        this.GetWidthRaw( ):   None                     this.GetWidthDefaultValue( ):   1                        this.GetWidthLen( ):   1    this.HasWidthGetterPrefix( ):   (<class 'int'>, <class 'bool'>)              this.GetWidthGetterPrefix( ):   None
this.IsDepthSet( ):   False     this.GetDepth( ):    2                        this.GetDepthRaw( ):   None                     this.GetDepthDefaultValue( ):   2                        this.GetDepthLen( ):   1    this.HasDepthGetterPrefix( ):   None                                         this.GetDepthGetterPrefix( ):   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ):  False     this.GetHeight( ):   0                        this.GetHeightRaw( ):  None                     this.GetHeightDefaultValue( ):  0                        this.GetHeightLen( ):  1    this.HasHeightGetterPrefix( ):  <class 'int'>                                this.GetHeightGetterPrefix( ):  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

وهذا بعد تعيين كل خصائص _foo (باستثناء الاسم) القيم التالية بنفس الترتيب: "السلسلة"، 1.0، TRUE، 9، 10، خطأ

this.IsNameSet( ):    True      this.GetName( ):     _foo                     this.GetNameRaw( ):    _foo                     this.GetNameDefaultValue( ):    AccessorFuncDemoClass    this.GetNameLen( ):    4    this.HasNameGetterPrefix( ):    <class 'str'>                                this.GetNameGetterPrefix( ):    None
this.IsXSet( ):       True      this.GetX( ):        10                       this.GetXRaw( ):       10                       this.GetXDefaultValue( ):       1111                     this.GetXLen( ):       2    this.HasXGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetXGetterPrefix( ):       None
this.IsYSet( ):       True      this.GetY( ):        10                       this.GetYRaw( ):       10                       this.GetYDefaultValue( ):       2222                     this.GetYLen( ):       2    this.HasYGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetYGetterPrefix( ):       None
this.IsZSet( ):       True      this.GetZ( ):        10                       this.GetZRaw( ):       10                       this.GetZDefaultValue( ):       3333                     this.GetZLen( ):       2    this.HasZGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetZGetterPrefix( ):       None
this.IsBlahSet( ):    True      this.GetBlah( ):     string Blah              this.GetBlahRaw( ):    string Blah              this.GetBlahDefaultValue( ):    <class 'int'>            this.GetBlahLen( ):    11   this.HasBlahGetterPrefix( ):    <class 'str'>                                this.GetBlahGetterPrefix( ):    None
this.IsWidthSet( ):   True      this.GetWidth( ):    False                    this.GetWidthRaw( ):   False                    this.GetWidthDefaultValue( ):   1                        this.GetWidthLen( ):   5    this.HasWidthGetterPrefix( ):   (<class 'int'>, <class 'bool'>)              this.GetWidthGetterPrefix( ):   None
this.IsDepthSet( ):   True      this.GetDepth( ):    9                        this.GetDepthRaw( ):   9                        this.GetDepthDefaultValue( ):   2                        this.GetDepthLen( ):   1    this.HasDepthGetterPrefix( ):   None                                         this.GetDepthGetterPrefix( ):   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ):  True      this.GetHeight( ):   9                        this.GetHeightRaw( ):  9                        this.GetHeightDefaultValue( ):  0                        this.GetHeightLen( ):  1    this.HasHeightGetterPrefix( ):  <class 'int'>                                this.GetHeightGetterPrefix( ):  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

_foo         --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016

    Key       Getter Value        | Raw Key   Raw / Stored Value       | Get Default Value             Default Value            | Get Allowed Types             Allowed Types                                                              | Get Allowed Values            Allowed Values                                                                                                                                                                                                                   |

    Name:     _foo                | _Name:    _foo                     | __Name.DefaultValue( ):       AccessorFuncDemoClass    | __Name.GetAllowedTypes( )     <class 'str'>                                                              | __Name.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    x:        10                  | _x:       10                       | __x.DefaultValue( ):          1111                     | __x.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __x.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    y:        10                  | _y:       10                       | __y.DefaultValue( ):          2222                     | __y.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __y.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    z:        10                  | _z:       10                       | __z.DefaultValue( ):          3333                     | __z.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __z.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Blah:     string Blah         | _Blah:    string Blah              | __Blah.DefaultValue( ):       <class 'int'>            | __Blah.GetAllowedTypes( )     <class 'str'>                                                              | __Blah.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Width:    False               | _Width:   False                    | __Width.DefaultValue( ):      1                        | __Width.GetAllowedTypes( )    (<class 'int'>, <class 'bool'>)                                            | __Width.GetAllowedValues( )   Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Height:   9                   | _Height:  9                        | __Height.DefaultValue( ):     0                        | __Height.GetAllowedTypes( )   <class 'int'>                                                              | __Height.GetAllowedValues( )  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |
    Depth:    9                   | _Depth:   9                        | __Depth.DefaultValue( ):      2                        | __Depth.GetAllowedTypes( )    Saved Value Restricted to Authorized Values ONLY                           | __Depth.GetAllowedValues( )   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |

لاحظ أنه نظرا لأن أنواع البيانات المحظورة أو قيود القيمة، لم يتم تعيين بعض البيانات - هذا حسب التصميم. يحظر STERTER أنواع أو قيم البيانات السيئة من التعيين، حتى من التعيينات كقيمة افتراضية (إلا إذا تجاوزت سلوك حماية القيمة الافتراضي)

لم يتم نشر الرمز هنا لأنني لم يكن لدي مجالا بعد الأمثلة والتفسيرات ... أيضا لأنه سيتغير.

يرجى ملاحظة: في وقت النشر، الملف فوضوي - سيغير هذا. ولكن، إذا قمت بتشغيله في نص سامي وتجميعه، أو تشغيله من Python، فسوف يترجم إليه ويبصق طن من المعلومات - لم يتم إجراء جزء AccessOrDB (الذي سيتم استخدامه لتحديث Getters Print and Getkeyoutput Helper وظائف جنبا إلى جنب مع تغييرها إلى وظيفة مثيل، ربما وضعت في وظيفة واحدة وإعادة تسميته - ابحث عنها ..)

التالي: ليس كل شيء مطلوب لتشغيله - الكثير من الأشياء المعلقة في الأسفل هو لمزيد من المعلومات المستخدمة في تصحيح الأخطاء - قد لا يكون هناك عند تنزيله. إذا كان الأمر كذلك، فيجب أن تكون قادرا على إعادة التوصل إلى الحصول على مزيد من المعلومات.

أنا أبحث عن عمل لحجز myclassbase: Pass، myclass (myclassbase): ... - إذا كنت تعرف حل - نشرها.

الشيء الوحيد الضروري في الفصل هي خطوط __ - ستر هو لتصحيح الأخطاء كما هو فيه - يمكن إزالتها من الطبقة التجريبية ولكن ستحتاج إلى التعليق أو إزالة بعض الخطوط أدناه (_foo / 2/3).

هي السلسلة والمواصفة، وفصول UTIL في الأعلى هي جزء من مكتبة Python الخاصة بي - فهي غير كاملة. قمت بنسخ أكثر من بعض الأشياء التي أحتاجها من المكتبة، وقد أنشأت بعضها البعض. سيرتبط الكود الكامل إلى المكتبة الكاملة وسيقوم بتضمينه مع توفير المكالمات المحدثة وإزالة التعليمات البرمجية (في الواقع، سيكون الكود المتبقي الوحيد سيكون الفصل التجريبي وبيانات الطباعة - سيتم نقل نظام AccessorFunc إلى المكتبة). ..

جزء من الملف:

##
## MyClass Test AccessorFunc Implementation for Dynamic 1-line Parameters
##
class AccessorFuncDemoClassBase( ):
    pass
class AccessorFuncDemoClass( AccessorFuncDemoClassBase ):
    __Name      = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Name',      default = 'AccessorFuncDemoClass',  allowed_types = ( TYPE_STRING ),                    allowed_values = VALUE_ANY,                 documentation = 'Name Docs',        getter_prefix = 'Get',  key = 'Name',       allow_erroneous_default = False,    options = { } )
    __x         = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'X',         default = 1111,                     allowed_types = ( TYPE_INTEGER, TYPE_FLOAT ),       allowed_values = VALUE_ANY,                 documentation = 'X Docs',           getter_prefix = 'Get',  key = 'x',          allow_erroneous_default = False,    options = { } )
    __Height    = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Height',    default = 0,                        allowed_types = TYPE_INTEGER,                       allowed_values = VALUE_SINGLE_DIGITS,       documentation = 'Height Docs',      getter_prefix = 'Get',  key = 'Height',     allow_erroneous_default = False,    options = { } )

هذا الجمال يجعل من السهل بشكل لا يصدق إنشاء فئات جديدة مع خصائص مضافة ديناميكيا مع AccessorFuncs / عمليات الاتصال / نوع البيانات / إنفاذ القيمة، إلخ.

في الوقت الحالي، يكون الرابط في (يجب أن يعكس هذا الرابط تغييرات في المستند.): https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py؟dl=0.

أيضا: إذا لم تستخدم النص السامي، أوصي به أكثر من المفكرة ++، Atom، التعليمات البرمجية المرئية، وغيرها بسبب تطبيقات الخيوط المناسبة مما يجعلها أسرع بكثير للاستخدام ... أنا أعمل أيضا على رمز مثل IDE نظام رسم الخرائط لذلك - إلقاء نظرة على: https://bitbucket.org/ACECOOL/ACECOOLCODEMAPTSYSTEM/SRC/Master/ (إضافة ريبو في إدارة الحزم أولا، ثم قم بتثبيت البرنامج المساعد - عند الإصدار 1.0.0 جاهز، سأضيفه إلى قائمة المساعدات البرنامجية الرئيسية ...)

آمل أن يساعد هذا الحل ... وكما هو الحال دائما:

فقط لأنها تعمل، لا تجعله بشكل صحيح - جوش "acecool" moser

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top