python ارطغرل 129 - باستخدام خاصية () على classmethods





7 Answers

يتم إنشاء خاصية على فئة ولكنها تؤثر على مثيل. لذلك إذا كنت تريد خاصية classmethod ، قم بإنشاء الخاصية على metaclass.

>>> class foo(object):
    _var = 5
    class __metaclass__(type):
        pass
    @classmethod
    def getvar(cls):
        return cls._var
    @classmethod
    def setvar(cls, value):
        cls._var = value


>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

ولكن بما أنك تستخدم metaclass على أي حال ، فستقرأ بشكل أفضل إذا قمت فقط بنقل classmethods هناك.

>>> class foo(object):
    _var = 5
    class __metaclass__(type):
        @property
        def var(cls):
            return cls._var
        @var.setter
        def var(cls, value):
            cls._var = value


>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
130 مترجم مسلسل

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

class Foo(object):
    _var = 5
    @classmethod
    def getvar(cls):
        return cls._var
    @classmethod
    def setvar(cls, value):
        cls._var = value
    var = property(getvar, setvar)

يمكنني توضيح أساليب الصف ، لكنهم لا يعملون كخصائص:

>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable

هل من الممكن استخدام خاصية property () مع وظائف classmethod مزينة؟




لا توجد طريقة معقولة لجعل هذا النظام "خاصية الصف" يعمل في بايثون.

هنا طريقة واحدة غير معقولة لجعلها تعمل. يمكنك بالتأكيد جعلها أكثر سلاسة مع كميات متزايدة من سحر metaclass.

class ClassProperty(object):
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter
    def __get__(self, cls, owner):
        return getattr(cls, self.getter)()
    def __set__(self, cls, value):
        getattr(cls, self.setter)(value)

class MetaFoo(type):
    var = ClassProperty('getvar', 'setvar')

class Foo(object):
    __metaclass__ = MetaFoo
    _var = 5
    @classmethod
    def getvar(cls):
        print "Getting var =", cls._var
        return cls._var
    @classmethod
    def setvar(cls, value):
        print "Setting var =", value
        cls._var = value

x = Foo.var
print "Foo.var = ", x
Foo.var = 42
x = Foo.var
print "Foo.var = ", x

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

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

ومع ذلك ، في تعليق على إجابة سابقة ، أنت تقول ذلك

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

يبدو لي ، ما تريده حقاً هو نمط تصميم Observer .




بايثون 3!

السؤال القديم ، الكثير من وجهات النظر ، في حاجة ماسة إلى طريقة بايثون 3 صحيح واحد.

لحسن الحظ ، فمن السهل مع metaclass metaclass:

class FooProperties(type):

    @property
    def var(cls):
        return cls._var

class Foo(object, metaclass=FooProperties):
    _var = 'FOO!'

ثم ، >>> Foo.var

"فو!




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

هل لديك حق الوصول إلى مثيل واحد على الأقل من الفصل الدراسي؟ يمكنني التفكير في طريقة للقيام بذلك بعد ذلك:

class MyClass (object):
    __var = None

    def _set_var (self, value):
        type (self).__var = value

    def _get_var (self):
        return self.__var

    var = property (_get_var, _set_var)

a = MyClass ()
b = MyClass ()
a.var = "foo"
print b.var



جرب هذه المحاولة ، فهي تنجز المهمة دون الحاجة إلى تغيير / إضافة الكثير من الشفرات الموجودة.

>>> class foo(object):
...     _var = 5
...     def getvar(cls):
...         return cls._var
...     getvar = classmethod(getvar)
...     def setvar(cls, value):
...         cls._var = value
...     setvar = classmethod(setvar)
...     var = property(lambda self: self.getvar(), lambda self, val: self.setvar(val))
...
>>> f = foo()
>>> f.var
5
>>> f.var = 3
>>> f.var
3

تحتاج property إلى callable . منحهم lambda wrappers (الذي يمر المثيل كوسيطة الأولى) وكل شيء على ما يرام.




بعد البحث في أماكن مختلفة ، وجدت طريقة لتعريف خاصية classproperty صالحة مع Python 2 و 3.

from future.utils import with_metaclass

class BuilderMetaClass(type):
    @property
    def load_namespaces(self):
        return (self.__sourcepath__)

class BuilderMixin(with_metaclass(BuilderMetaClass, object)):
    __sourcepath__ = 'sp'        

print(BuilderMixin.load_namespaces)

آمل أن هذا يمكن أن يساعد شخص ما :)




هنا اقتراحي. لا تستخدم طرق الصف.

بشكل جاد.

ما هو سبب استخدام طرق الصف في هذه الحالة؟ لماذا لا يكون لديك موضوع عادي لطبقة عادية؟

إذا كنت ترغب ببساطة في تغيير القيمة ، فإن العقار ليس مفيدًا حقًا في الواقع؟ ما عليك سوى تعيين قيمة السمة والقيام بها.

يجب استخدام الخاصية فقط إذا كان هناك شيء لإخفائه - وهو أمر قد يتغير في التنفيذ في المستقبل.

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

تقنيات "الخصوصية" المتأثرة بالجافا (في Python ، أسماء السمات التي تبدأ بـ _) ليست مفيدة جدًا حقًا. خاص من من؟ النقطة الخاصة هي غامضة قليلاً عندما يكون لديك المصدر (كما تفعل في بايثون.)

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




Related


Tags

python   oop