पायथन में @ foo.setter मेरे लिए काम क्यों नहीं करता है?


155

इसलिए, मैं पायथन 2.6 में सज्जाकारों के साथ खेल रहा हूं, और मुझे उन्हें काम करने में कुछ परेशानी हो रही है। यहाँ मेरी कक्षा फ़ाइल है:

class testDec:

    @property
    def x(self): 
        print 'called getter'
        return self._x

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

मुझे लगा कि इसका मतलब xएक संपत्ति की तरह व्यवहार करना है, लेकिन इन कार्यों को कॉल करें और सेट करें। इसलिए, मैंने IDLE को निकाल दिया और इसकी जाँच की:

>>> from testDec import testDec
from testDec import testDec
>>> t = testDec()
t = testDec()
>>> t.x
t.x
called getter
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "testDec.py", line 18, in x
    return self._x
AttributeError: testDec instance has no attribute '_x'
>>> t.x = 5
t.x = 5
>>> t.x
t.x
5

स्पष्ट रूप से पहली कॉल अपेक्षा के अनुसार काम करती है, क्योंकि मैं गेट्टर को कॉल करता हूं, और कोई डिफ़ॉल्ट मान नहीं है, और यह विफल रहता है। ठीक है, अच्छा, मैं समझता हूं। हालाँकि, कॉल करने के लिए कॉल t.x = 5एक नई संपत्ति बनाने के लिए लगता है x, और अब गेट्टर काम नहीं करता है!

मैं क्या खो रहा हूँ?


6
कृपया एक बड़े अक्षर के साथ वर्गों का नाम दें। आप चर और मॉड्यूल फ़ाइलों के लिए लोअरकेस का उपयोग कर सकते हैं।
S.Lott

जवाबों:


306

आपको लगता है कि क्लासिक पुरानी शैली की कक्षाओं का उपयोग अजगर 2 में किया जा रहा है। गुणों को सही ढंग से काम करने के लिए आपको इसके बजाय नई शैली की कक्षाओं का उपयोग करने की आवश्यकता है (अजगर 2 में आपको विरासत मेंobject मिलनी चाहिए )। बस अपनी कक्षा को इस रूप में घोषित करें MyClass(object):

class testDec(object):

    @property
    def x(self): 
        print 'called getter'
        return self._x

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

यह काम करता हैं:

>>> k = testDec()
>>> k.x
called getter
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/devel/class_test.py", line 6, in x
    return self._x
AttributeError: 'testDec' object has no attribute '_x'
>>> k.x = 5
called setter
>>> k.x
called getter
5
>>> 

एक और विस्तार जो समस्या पैदा कर सकता है वह यह है कि दोनों विधियों को काम करने के लिए संपत्ति के लिए समान नाम की आवश्यकता है। यदि आप सेटर को किसी भिन्न नाम से परिभाषित करते हैं तो यह काम नहीं करेगा :

@x.setter
def x_setter(self, value):
    ...

और एक और चीज जो पहली बार में पूरी तरह से आसान नहीं है, वह है आदेश: गेट्टर को पहले परिभाषित किया जाना चाहिए । यदि आप पहले सेटर को परिभाषित करते हैं, तो आपको name 'x' is not definedत्रुटि मिलती है।


4
Python3 में यह आवश्यक नहीं है - "क्लासिक" वर्ग
बसने वालों के

20
यह अजगर 3 में काम करता है क्योंकि हर वर्ग एक नई शैली की कक्षा है, अब कोई 'क्लासिक' कक्षाएं नहीं हैं।
पुष्टि करता है

मुझे लगता है कि किसी को चेतावनी / त्रुटि मिलनी चाहिए, अगर इस मामले में डेकोरेटर को सही ढंग से संसाधित नहीं किया गया है।
stfn

82

इस अपवाद की तलाश में यहां ठोकर खाने वाले अन्य लोगों के लिए बस एक नोट: दोनों कार्यों को एक ही नाम की आवश्यकता है। निम्नानुसार विधियों का नामकरण एक अपवाद के रूप में होगा:

@property
def x(self): pass

@x.setter
def x_setter(self, value): pass

इसके बजाय दोनों तरीकों को एक ही नाम दें

@property
def x(self): pass

@x.setter
def x(self, value): pass

यह नोट करना भी महत्वपूर्ण है कि घोषणा का क्रम मायने रखता है। फ़ाइल में सेटर से पहले गेटर को परिभाषित किया जाना चाहिए अन्यथा आपको एNameError: name 'x' is not defined


यह शायद पायथन 3 पर अधिक से अधिक लोगों के साथ "नया" सर्वश्रेष्ठ उत्तर बनने जा रहा है ...
trpt4him

5
यह उत्तर बहुत अच्छा है। मुझे लगता है कि पूरा होने के लिए, यह बहुत अच्छा होगा यदि आप टिप्पणी कर सकते हैं कि आदेश महत्वपूर्ण है, अर्थात कोड में सेटर से पहले गेटर होना चाहिए। अन्यथा, आपको एक NameError: name 'x' is not definedअपवाद मिलेगा ।
eguaio

इसके लिए धन्यवाद। मैंने इस पर सिर्फ एक दिन का सबसे अच्छा हिस्सा बर्बाद किया। यह मेरे लिए कभी नहीं हुआ कि विधियों को एक ही चीज़ कहा जाना था। वास्तव में निराशा में थोड़ा मुहावरा!
अंजनाघघ

इस उत्तर के पीछे "क्यों" को समझने के लिए, यहां निश्चित दस्तावेज पढ़ें: docs.python.org/2/library/functions.html#property विशेष रूप से "बिल्कुल समतुल्य" भाग पर ध्यान दें।
इवगेनी सर्गेव

23

आपको नई शैली की कक्षाओं का उपयोग करने की आवश्यकता है जो आप अपनी कक्षा को ऑब्जेक्ट से प्राप्त करके करते हैं:

class testDec(object):
   ....

फिर यह काम करना चाहिए।


ऊपर सब कुछ यथावत था। कक्षाओं में गुणों के लिए ठीक से किक करने के लिए मुझे अजगर 2.7.x में इसकी आवश्यकता थी।
ड्रोन ब्रेन

12

यदि कोई व्यक्ति Google से यहां आता है, तो उपरोक्त उत्तरों के अलावा, मैं यह जोड़ना चाहूंगा कि इस उत्तर के__init__ आधार पर आपकी कक्षा की विधि से सेटर को आमंत्रित करते समय इस पर विशेष ध्यान देने की आवश्यकता है :

class testDec(object):                                                                                                                                            

    def __init__(self, value):
        print 'We are in __init__'
        self.x = value # Will call the setter. Note just x here
        #self._x = value # Will not call the setter

    @property
    def x(self):
        print 'called getter'
        return self._x # Note the _x here

    @x.setter
    def x(self, value): 
        print 'called setter'
        self._x = value # Note the _x here

t = testDec(17)
print t.x 

Output:
We are in __init__
called setter
called getter
17

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