Classmethods पर संपत्ति () का उपयोग करना


173

मेरे पास दो क्लास मेथड्स (क्लासमेथोड (फंक्शन फंक्शन का उपयोग करके) प्राप्त करने और स्थापित करने के लिए एक क्लास है जो अनिवार्य रूप से एक स्थिर चर है। मैंने इन के साथ संपत्ति () फ़ंक्शन का उपयोग करने की कोशिश की, लेकिन इसका परिणाम त्रुटि है। मैं दुभाषिया में निम्नलिखित के साथ त्रुटि को पुन: उत्पन्न करने में सक्षम था:

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

क्या क्लासमेथोड सजाया कार्यों के साथ संपत्ति () फ़ंक्शन का उपयोग करना संभव है?

जवाबों:


90

एक संपत्ति एक वर्ग पर बनाई गई है लेकिन एक उदाहरण को प्रभावित करती है। इसलिए यदि आप एक क्लासमेथोड संपत्ति चाहते हैं, तो मेटाक्लास पर संपत्ति बनाएं।

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         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

लेकिन जब से आप वैसे भी एक मेटाक्लस का उपयोग कर रहे हैं, तो यह बेहतर होगा कि अगर आप क्लासमैथोड्स को वहां ले जाते हैं।

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         @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

या, पायथन 3 के metaclass=...सिंटैक्स का उपयोग करके , और fooवर्ग निकाय के बाहर परिभाषित किए गए मेटाक्लास और प्रारंभिक मूल्य निर्धारित करने के लिए जिम्मेदार मेटाक्लास _var:

>>> class foo_meta(type):
...     def __init__(cls, *args, **kwargs):
...         cls._var = 5
...     @property
...     def var(cls):
...         return cls._var
...     @var.setter
...     def var(cls, value):
...         cls._var = value
...
>>> class foo(metaclass=foo_meta):
...     pass
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

1
यह मेरे लिए पायथन 3.2 में काम नहीं करता है। अगर मैं फू। "foo.var" को निष्पादित करते समय ऑब्जेक्ट 'foo' की कोई विशेषता 'var' नहीं है।
माइकल केली

आह डबल सुधार: इस अजगर 2.7 में काम करता है, लेकिन नहीं अजगर 3.2।
माइकल केली

@MichaelKelley - ऐसा इसलिए है क्योंकि मेटाक्लास के
मैक

1
मैं यह समझने के लिए बिल्कुल निश्चित नहीं हूं कि इसे लिखने के लिए पायथन 3.x तरीका क्या होगा?
सिल्वेनैड

8
@ जोसे: आपको पहले मेटाक्लस को परिभाषित करना होगा, फिर नए class Foo(metaclass=...)सिंटैक्स का उपयोग करके कक्षा को परिभाषित करना होगा ।
केविन

69

पायथन 2.2 रिलीज नोट्स को पढ़ना , मुझे निम्नलिखित लगता है।

जब संपत्ति को वर्ग विशेषता (Cx) के रूप में एक्सेस किया जाता है, तो उदाहरण विधि (C () x) के बजाय विधि को प्राप्त नहीं किया जाएगा। यदि आप एक वर्ग विशेषता के रूप में उपयोग किए जाने वाले गुणों के लिए __get__ ऑपरेशन को ओवरराइड करना चाहते हैं, तो आप संपत्ति को उप-वर्ग कर सकते हैं - यह स्वयं एक नई शैली का प्रकार है - इसकी __get__ विधि का विस्तार करने के लिए, या आप एक नया बनाने के लिए स्क्रैच प्रकार को परिभाषित कर सकते हैं -स्टाइल वर्ग जो __get__, __set__ और __delete__ विधियों को परिभाषित करता है।

नोट: नीचे की विधि वास्तव में बसने वालों के लिए काम नहीं करती है, केवल गेटर्स।

इसलिए, मेरा मानना ​​है कि निर्धारित समाधान संपत्ति के उपवर्ग के रूप में क्लासप्रॉपर्टी बनाना है।

class ClassProperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()

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=ClassProperty(getvar,setvar)

assert foo.getvar() == 5
foo.setvar(4)
assert foo.getvar() == 4
assert foo.var == 4
foo.var = 3
assert foo.var == 3

हालाँकि, वासी वास्तव में काम नहीं करते हैं:

foo.var = 4
assert foo.var == foo._var # raises AssertionError

foo._var अपरिवर्तित है, आपने बस एक नए मूल्य के साथ संपत्ति को अधिलेखित कर दिया है।

आप ClassPropertyएक डेकोरेटर के रूप में भी उपयोग कर सकते हैं :

class foo(object):
    _var = 5

    @ClassProperty
    @classmethod
    def var(cls):
        return cls._var

    @var.setter
    @classmethod
    def var(cls, value):
        cls._var = value

assert foo.var == 5

20
मुझे नहीं लगता कि ClassProperty का सेटर हिस्सा वास्तव में वर्णित के रूप में काम करता है: जबकि उदाहरण के दावे सभी पास हैं, अंत में foo._var == 4 (3 नहीं, जैसा कि निहित है)। संपत्ति को सेट करना संपत्ति को स्वयं ही बंद कर देता है। जब अजगर-देव पर वर्ग-गुणों पर चर्चा की गई थी, तो यह बताया गया था कि गेटर्स तुच्छ हैं, बसने वाले एक मेटाकॉल के बिना मुश्किल (असंभव?) हैं
गेब्रियल ग्रांट

4
@ गैब्रिएल पूरी तरह से सही है। मैं विश्वास नहीं कर सकता कि कोई भी दो साल के लिए बाहर बताया।
एएफएफ

मुझे यह भी यकीन नहीं है कि आप यहां सिर्फ self.fget(owner)एक का उपयोग करने की आवश्यकता क्यों नहीं निकालते और हटाते @classmethodहैं? (है कि क्या classmethod करता है , उसका अनुवाद .__get__(instance, owner)(*args, **kwargs)करने के लिए function(owner, *args, **kwargs)कॉल, एक मध्यस्थ के माध्यम से, गुण मध्यस्थ की जरूरत नहीं है)।
मार्टिन पीटर्स

आपके प्रदर्शन में गटर या सेटर में किसी भी वास्तविक परिवर्तन का अभाव है जो बड़े करीने से प्रदर्शित करेगा कि आपका foo.var = 3असाइनमेंट वास्तव में संपत्ति के माध्यम से नहीं जाता है , और इसके बजाय केवल fooएक पूर्णांक के साथ संपत्ति ऑब्जेक्ट को बदल दिया है । यदि आप assert isinstance(foo.__dict__['var'], ClassProperty)अपने दावे के बीच कॉल जोड़ते हैं तो आप देखेंगे कि foo.var = 3निष्पादित होने के बाद विफल हो जाते हैं ।
मार्टिन पीटर्स

1
अजगर वर्गों की स्थापना के लिए बाध्यकारी समर्थन वर्णनकर्ता नहीं है वर्ग पर ही , केवल प्राप्त करने पर (ताकि instance.attr, instance.attr = valueऔर del instance.attrसब बाँध वर्णनकर्ता पर पाया जाएगा type(instance), लेकिन जब classobj.attrबांधता है, classobj.attr = valueऔर del classobj.attrहै नहीं है और इसके बजाय बदलने के लिए या वर्णनकर्ता वस्तु ही हटा सकते हैं)। सेटिंग और डिलीट करने के लिए आपको एक मेटाक्लस की आवश्यकता होती है (क्लास ऑब्जेक्ट को इंस्टेंस बनाते हुए, और मेटाक्लस टाइप)।
मार्टिन पीटर्स

56

मुझे उम्मीद है कि यह मृत-सरल पठन-योग्य केवल @classpropertyसज्जाकार किसी को क्लासप्रॉपरेटी की तलाश में मदद करेगा।

class classproperty(object):

    def __init__(self, fget):
        self.fget = fget

    def __get__(self, owner_self, owner_cls):
        return self.fget(owner_cls)

class C(object):

    @classproperty
    def x(cls):
        return 1

assert C.x == 1
assert C().x == 1

2
क्या यह उपवर्गों के साथ काम करता है? (क्या एक उपवर्ग क्लासप्रिपरेटी को ओवरराइड कर सकता है?)
zakdances

1
उम्म हाँ? class D(C): x = 2; assert D.x == 2
डेथोडर

काश यह काम किया जब मैं में उपयोग .formatकी तरह "{x}".format(**dict(self.__class__.__dict__, **self.__dict__)):(
2rs2ts

@ नथन ही नहीं ... जब आप इसे सेट करते हैं तो आप सभी xपहुँच को ओवरराइड करते हैं 10। मुझे यह तरीका पसंद है क्योंकि साफ-सुथरा और सरल है, लेकिन एक एंटीपैटर की तरह लगता है
मिशेल

आसानी से तय: ओवरराइड को रोकने के लिए __set__एक उठाता है कि जोड़ें ValueError
किरण जोनलगड्डा

30

क्या क्लासमेथोड सजाया कार्यों के साथ संपत्ति () फ़ंक्शन का उपयोग करना संभव है?

नहीं।

हालाँकि, एक classmethod उस वर्ग के उदाहरणों से सुलभ एक वर्ग पर एक बाउंड मेथड (आंशिक कार्य) है।

चूंकि उदाहरण वर्ग का एक कार्य है और आप कक्षा को उदाहरण से प्राप्त कर सकते हैं, इसलिए आप वर्ग-संपत्ति से जो भी वांछित व्यवहार प्राप्त कर सकते हैं उसे प्राप्त कर सकते हैं property:

class Example(object):
    _class_property = None
    @property
    def class_property(self):
        return self._class_property
    @class_property.setter
    def class_property(self, value):
        type(self)._class_property = value
    @class_property.deleter
    def class_property(self):
        del type(self)._class_property

इस कोड का उपयोग परीक्षण करने के लिए किया जा सकता है - इसे बिना किसी त्रुटि के पास करना चाहिए:

ex1 = Example()
ex2 = Example()
ex1.class_property = None
ex2.class_property = 'Example'
assert ex1.class_property is ex2.class_property
del ex2.class_property
assert not hasattr(ex1, 'class_property')

और ध्यान दें कि हमें मेटाक्लास की बिल्कुल भी आवश्यकता नहीं थी - और आप सीधे अपनी कक्षाओं के माध्यमों से मेटाक्लास तक नहीं पहुँच सकते हैं।

@classpropertyडेकोरेटर लिखना

आप वास्तव classpropertyमें उप-वर्ग द्वारा कोड की कुछ पंक्तियों में एक डेकोरेटर बना सकते हैं property(यह सी में लागू है, लेकिन आप यहां बराबर पायथन देख सकते हैं ):

class classproperty(property):
    def __get__(self, obj, objtype=None):
        return super(classproperty, self).__get__(objtype)
    def __set__(self, obj, value):
        super(classproperty, self).__set__(type(obj), value)
    def __delete__(self, obj):
        super(classproperty, self).__delete__(type(obj))

फिर डेकोरेटर का इलाज करें जैसे कि वह एक संपत्ति के साथ एक वर्गमोहक था:

class Foo(object):
    _bar = 5
    @classproperty
    def bar(cls):
        """this is the bar attribute - each subclass of Foo gets its own.
        Lookups should follow the method resolution order.
        """
        return cls._bar
    @bar.setter
    def bar(cls, value):
        cls._bar = value
    @bar.deleter
    def bar(cls):
        del cls._bar

और यह कोड त्रुटियों के बिना काम करना चाहिए:

def main():
    f = Foo()
    print(f.bar)
    f.bar = 4
    print(f.bar)
    del f.bar
    try:
        f.bar
    except AttributeError:
        pass
    else:
        raise RuntimeError('f.bar must have worked - inconceivable!')
    help(f)  # includes the Foo.bar help.
    f.bar = 5

    class Bar(Foo):
        "a subclass of Foo, nothing more"
    help(Bar) # includes the Foo.bar help!
    b = Bar()
    b.bar = 'baz'
    print(b.bar) # prints baz
    del b.bar
    print(b.bar) # prints 5 - looked up from Foo!

    
if __name__ == '__main__':
    main()

लेकिन मुझे यकीन नहीं है कि यह कितना अच्छा होगा। एक पुराना मेलिंग सूची लेख बताता है कि उसे काम नहीं करना चाहिए।

वर्ग पर काम करने के लिए संपत्ति प्राप्त करना:

ऊपर का नकारात्मक पक्ष यह है कि "वर्ग संपत्ति" वर्ग से सुलभ नहीं है, क्योंकि यह बस वर्ग से डेटा डिस्क्रिप्टर को अधिलेखित कर देगा __dict__

हालाँकि, हम मेटाक्लस में परिभाषित संपत्ति के साथ इसे ओवरराइड कर सकते हैं __dict__। उदाहरण के लिए:

class MetaWithFooClassProperty(type):
    @property
    def foo(cls):
        """The foo property is a function of the class -
        in this case, the trivial case of the identity function.
        """
        return cls

और फिर मेटाक्लास का एक वर्ग उदाहरण में एक संपत्ति हो सकती है जो पहले से पहले अनुभागों में प्रदर्शित सिद्धांत का उपयोग करके वर्ग की संपत्ति तक पहुंचती है:

class FooClassProperty(metaclass=MetaWithFooClassProperty):
    @property
    def foo(self):
        """access the class's property"""
        return type(self).foo

और अब हम दोनों उदाहरण देखते हैं

>>> FooClassProperty().foo
<class '__main__.FooClassProperty'>

और वर्ग

>>> FooClassProperty.foo
<class '__main__.FooClassProperty'>

वर्ग की संपत्ति तक पहुँच है।


3
स्पष्ट, संक्षिप्त, संपूर्ण: यह स्वीकृत उत्तर होना चाहिए।
pfabri

25

अजगर 3!

पुराने प्रश्न, बहुत सारे विचार, एक सच्चे पायथन 3 तरीके की आवश्यकता के अनुसार।

सौभाग्य से, यह metaclasskwarg के साथ आसान है :

class FooProperties(type):

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

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

फिर, >>> Foo.var

'FOO!'


1
यह कहना है कि बॉक्स से बाहर कोई सरल तरीका नहीं है
mehmet

@mehmet क्या यह सरल नहीं है? Fooइसके मेटाक्लस का एक उदाहरण है, और @propertyइसके तरीकों के लिए इस्तेमाल किया जा सकता है जैसे कि उन उदाहरणों के लिए Foo
ओजफ़र्ड

2
आपको एक वर्ग के लिए दूसरी कक्षा को परिभाषित करना था, जो कि यह जटिलता दोगुना है कि मेटाक्लस पुन: प्रयोज्य नहीं है।
mehmet

एक classmethod वर्ग और उदाहरण दोनों से काम करता है। यह संपत्ति केवल वर्ग से काम करती है। मुझे नहीं लगता कि यह वही है जो पूछा जा रहा है।
आरोन हॉल

1
@AaronHall यदि यह महत्वपूर्ण है, तो यह आसानी से जुड़ जाता है Foo.__new__। हालांकि उस बिंदु पर यह या तो getattribute का उपयोग करने के लायक हो सकता है, या सवाल कर रहा है कि क्या एक भाषा सुविधा का अस्तित्व मौजूद है, वास्तव में वह दृष्टिकोण है जिसे आप बिल्कुल लेना चाहते हैं।
OJFord

16

पायथन में काम करने के लिए इस "क्लास प्रॉपर्टी" सिस्टम को बनाने का कोई उचित तरीका नहीं है।

यहाँ यह काम करने का एक अनुचित तरीका है। आप निश्चित रूप से मेटाक्लास जादू की बढ़ती मात्रा के साथ इसे अधिक सहज बना सकते हैं।

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

इस मुद्दे की गुत्थी यह है कि प्रॉपर्टीज को "डिस्क्रिप्टर" कहा जाता है। यह समझाने का कोई छोटा और आसान तरीका नहीं है कि इस प्रकार के मेटाप्रोग्रामिंग कैसे काम करते हैं, इसलिए मुझे आपको विवरणक के लिए इंगित करना होगा ।

आपको कभी भी इस तरह की चीजों को समझने की जरूरत है यदि आप एक काफी उन्नत रूपरेखा को लागू कर रहे हैं। एक पारदर्शी वस्तु दृढ़ता या आरपीसी प्रणाली, या एक प्रकार की डोमेन-विशिष्ट भाषा की तरह।

हालांकि, एक पिछले जवाब के लिए एक टिप्पणी में, आप कहते हैं कि आप

एक विशेषता को संशोधित करने की आवश्यकता है कि इस तरह से एक वर्ग के सभी उदाहरणों को देखा जाता है, और जिस दायरे से इन वर्ग विधियों को बुलाया जाता है, उसमें कक्षा के सभी उदाहरणों के संदर्भ नहीं होते हैं।

यह मुझे लगता है, जो आप वास्तव में चाहते हैं वह एक ऑब्जर्वर डिजाइन पैटर्न है।


मुझे कोड उदाहरण का विचार पसंद है, लेकिन ऐसा लगता है कि यह व्यवहार में थोड़ा क्लंकी होगा।
मार्क रोड्डी

जो मैं पूरा करने की कोशिश कर रहा हूं वह बहुत ही सीधे फॉरवर्ड सेटिंग है और एक ही विशेषता की प्राप्ति है जिसे सभी उदाहरणों के व्यवहार को संशोधित करने के लिए एक ध्वज के रूप में उपयोग किया जाता है, इसलिए मुझे लगता है कि जो मैं करने की कोशिश कर रहा हूं उसके लिए ऑब्जर्वर ओवरब्लॉब होगा। यदि प्रश्न में कई गुण थे तो मैं अधिक इच्छुक होऊंगा।
मार्क रोड्डी

ऐसा लगता है कि बस कार्यों को सार्वजनिक करना और उन्हें सीधे कॉल करना सरल उपाय था। मैं उत्सुक था अगर मैं कुछ गलत कर रहा था या अगर मैं करने की कोशिश कर रहा था तो असंभव था। जिस तरह से कई टिप्पणियों के बारे में क्षमा करें। 300 चरित्र सीमा बेकार है।
मार्क रोड्डी

कोड उदाहरण के बारे में निफ्टी बात यह है कि आप सभी क्लंकी बिट्स को एक बार लागू कर सकते हैं और फिर उन्हें वारिस कर सकते हैं। बस _वर को व्युत्पन्न वर्ग में ले जाएँ। class D1 (Foo): _var = 21 class D2 (Foo) _var = "Hello" D1.var 21 D2.var हैलो
थॉमस एल होलाडे

6

केवल मेटा क्लास पर इसे सेट करने से मदद नहीं मिलती है यदि आप एक त्वरित ऑब्जेक्ट के माध्यम से वर्ग की संपत्ति तक पहुंचना चाहते हैं, तो इस मामले में आपको ऑब्जेक्ट पर एक सामान्य संपत्ति स्थापित करने की आवश्यकता है (जो वर्ग संपत्ति को भेजती है)। मुझे लगता है कि निम्नलिखित कुछ अधिक स्पष्ट है:

#!/usr/bin/python

class classproperty(property):
    def __get__(self, obj, type_):
        return self.fget.__get__(None, type_)()

    def __set__(self, obj, value):
        cls = type(obj)
        return self.fset.__get__(None, cls)(value)

class A (object):

    _foo = 1

    @classproperty
    @classmethod
    def foo(cls):
        return cls._foo

    @foo.setter
    @classmethod
    def foo(cls, value):
        cls.foo = value

a = A()

print a.foo

b = A()

print b.foo

b.foo = 5

print a.foo

A.foo = 10

print b.foo

print A.foo

3

आधा समाधान, वर्ग पर __set__ काम नहीं करता है, फिर भी। समाधान एक संपत्ति और एक स्थैतिक दोनों को लागू करने वाला एक कस्टम संपत्ति वर्ग है

class ClassProperty(object):
    def __init__(self, fget, fset):
        self.fget = fget
        self.fset = fset

    def __get__(self, instance, owner):
        return self.fget()

    def __set__(self, instance, value):
        self.fset(value)

class Foo(object):
    _bar = 1
    def get_bar():
        print 'getting'
        return Foo._bar

    def set_bar(value):
        print 'setting'
        Foo._bar = value

    bar = ClassProperty(get_bar, set_bar)

f = Foo()
#__get__ works
f.bar
Foo.bar

f.bar = 2
Foo.bar = 3 #__set__ does not

3

क्योंकि मुझे एक विशेषता को संशोधित करने की आवश्यकता है, जो इस तरह से एक वर्ग के सभी उदाहरणों द्वारा देखी जाती है, और जिस दायरे से इन वर्ग विधियों को बुलाया जाता है, उसमें कक्षा के सभी उदाहरणों के संदर्भ नहीं होते हैं।

क्या आपके पास कक्षा के कम से कम एक उदाहरण तक पहुंच है? मैं इसे करने का एक तरीका सोच सकता हूँ:

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

2

इसे आज़माएं, यह बहुत सारे मौजूदा कोड को बदलने / जोड़ने के बिना काम पूरा करता है।

>>> 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तर्क। उन्हें लैम्ब्डा रैपर दें (जो इसके पहले तर्क के रूप में उदाहरण के रूप में उत्तीर्ण होता है) और सब ठीक है।


जैसा कि फ्लोरियन बोश बताते हैं, आवश्यक वाक्य-विन्यास (तृतीय-पक्ष लाइब्रेरी या विरासत कोड द्वारा) foo.var है।
थॉमस एल होलाडे

2

यहां एक समाधान है जो वर्ग के माध्यम से पहुंच और एक उदाहरण के माध्यम से एक्सेस करने के लिए काम करना चाहिए जो मेटाक्लस का उपयोग करता है।

In [1]: class ClassPropertyMeta(type):
   ...:     @property
   ...:     def prop(cls):
   ...:         return cls._prop
   ...:     def __new__(cls, name, parents, dct):
   ...:         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
   ...:         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
   ...:         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
   ...:         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
   ...:

In [2]: class ClassProperty(object):
   ...:     __metaclass__ = ClassPropertyMeta
   ...:     _prop = 42
   ...:     def __getattr__(self, attr):
   ...:         raise Exception('Never gets called')
   ...:

In [3]: ClassProperty.prop
Out[3]: 42

In [4]: ClassProperty.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-e2e8b423818a> in <module>()
----> 1 ClassProperty.prop = 1

AttributeError: can't set attribute

In [5]: cp = ClassProperty()

In [6]: cp.prop
Out[6]: 42

In [7]: cp.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-e8284a3ee950> in <module>()
----> 1 cp.prop = 1

<ipython-input-1-16b7c320d521> in <lambda>(cls, attr, val)
      6         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
      7         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
----> 8         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
      9         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)

AttributeError: can't set attribute

यह मेटाक्लस में निर्धारित एक सेटर के साथ भी काम करता है।


1

विभिन्न स्थानों की खोज करने के बाद, मुझे पायथन 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)

आशा है कि यह किसी की मदद कर सकता है :)


1
यदि यह विधि आपको कहीं मिली है, तो एक लिंक देना अच्छा होगा (देखें कि दूसरों द्वारा लिखी गई संदर्भ सामग्री को कैसे देखें )
एंड्रयू मायर्स

-27

यहाँ मेरा सुझाव है। कक्षा विधियों का उपयोग न करें।

गंभीरता से।

इस मामले में कक्षा के तरीकों का उपयोग करने का कारण क्या है? एक साधारण वर्ग की साधारण वस्तु क्यों नहीं है?


यदि आप केवल मूल्य बदलना चाहते हैं, तो एक संपत्ति वास्तव में बहुत उपयोगी नहीं है? बस विशेषता मान सेट करें और इसके साथ किया जाए।

एक संपत्ति का उपयोग केवल तभी किया जाना चाहिए यदि कुछ छिपाने के लिए है - ऐसा कुछ जो भविष्य के कार्यान्वयन में बदल सकता है।

हो सकता है कि आपका उदाहरण नीचे छीन लिया गया हो, और आपके द्वारा छोड़ी गई कुछ नारकीय गणना हो। लेकिन ऐसा नहीं लगता कि संपत्ति महत्वपूर्ण मूल्य जोड़ती है।

जावा-प्रभावित "गोपनीयता" तकनीक (पायथन में, विशेषता नाम जो _ से शुरू होते हैं) वास्तव में बहुत उपयोगी नहीं हैं। प्राइवेट किससे? जब आपके पास स्रोत (जैसा कि आप पायथन में करते हैं) निजी की बात थोड़ी नीरस है।

जावा से प्रभावित ईजेबी-शैली के गेटर्स और सेटर (अक्सर पायथन में गुणों के रूप में किए गए) जावा के आदिम आत्मनिरीक्षण की सुविधा के साथ-साथ स्थैतिक भाषा संकलक के साथ मस्टर को पास करने के लिए हैं। वे सभी गेटर्स और सेटर पाइथन में सहायक नहीं हैं।


14
क्योंकि मुझे एक विशेषता को संशोधित करने की आवश्यकता है, जो इस तरह से एक वर्ग के सभी उदाहरणों द्वारा देखी जाती है, और जिस दायरे से इन वर्ग विधियों को बुलाया जाता है, उसमें कक्षा के सभी उदाहरणों के संदर्भ नहीं होते हैं।
मार्क रोडी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.