2012-08-16 13 views
10

मैं एक पायथन संपत्ति बनाने की कोशिश कर रहा हूं जहां मूल्य को पुनः प्राप्त करने के अलावा, अलग-अलग विधि द्वारा इन-प्लेस जोड़ने को संभाला जा रहा है, एक और मूल्य जोड़ना और पुन: असाइन करना। तो, एक वस्तु o पर एक संपत्ति x, के लिएएक पायथन संपत्ति के लिए __iadd__ को कार्यान्वित करने के लिए कैसे करें

o.x += 5 

से

o.x = o.x + 5 

अलग तरह से काम करना चाहिए o.x का मूल्य, अंत में एक ही होना चाहिए, ताकि लोगों की उम्मीदों भ्रमित करने के लिए नहीं है, लेकिन मैं इन-जगह को और अधिक कुशल बनाना चाहता हूं। (वास्तविकता में आपरेशन सरल इसके अलावा तुलना में बहुत अधिक समय लगता है।)

मेरा पहला विचार कक्षा में परिभाषित करने के लिए, था,

x = property(etc. etc.) 
x.__iadd__ = my_iadd 

लेकिन यह क्योंकि property लागू करता __slots__ एक AttributeError, शायद जन्म देती है?

class IAddProp(object): 
    def __init__(self): 
     self._val = 5 

    def __get__(self, obj, type=None): 
     return self._val 

    def __set__(self, obj, value): 
     self._val = value 

    def __iadd__(self, value): 
     print '__iadd__!' 
     self._val += value 
     return self 

class TestObj(object): 
    x = IAddProp() 
    #x.__iadd__ = IAddProp.__iadd__ # doesn't help 

>>> o = TestObj() 
>>> print o.x 
5 
>>> o.x = 10 
>>> print o.x 
10 
>>> o.x += 5 # '__iadd__!' not printed 
>>> print o.x 
15 

आप देख सकते हैं, विशेष __iadd__ विधि नहीं बुलाया जाता है:

मेरा अगला प्रयास की जानकारी देता वस्तु का उपयोग करता है। मुझे यह समझने में परेशानी हो रही है कि यह क्यों है, हालांकि मैं अनुमान लगाता हूं कि ऑब्जेक्ट का __getattr__ किसी भी तरह से इसे बाईपास कर रहा है।

मैं यह कैसे कर सकता हूं? क्या मुझे वर्णनकर्ताओं का मुद्दा नहीं मिल रहा है? क्या मुझे मेटाक्लास चाहिए?

उत्तर

6

__iadd__ केवल __get__ से लौटाए गए मूल्य पर ध्यान दिया जाएगा। आपको __get__ (या संपत्ति गेटटर) __iadd__ के साथ ऑब्जेक्ट (या प्रॉक्सी ऑब्जेक्ट) वापस करने की आवश्यकता है।

@property 
def x(self): 
    proxy = IProxy(self._x) 
    proxy.parent = self 
    return proxy 

class IProxy(int, object): 
    def __iadd__(self, val): 
     self.parent.iadd_x(val) 
     return self.parent.x 
+0

मैं इस कोड स्निपेट द्वारा थोड़ा उलझन में हूं। संपत्ति प्राप्तकर्ता कुछ वापस नहीं करना चाहिए? – senderle

+0

@sendle ओह हाँ, ओह। 'Int' subclassing की समस्याओं के साथ थोड़ा उलझन में मिला। धन्यवाद! – ecatmur

1

आपको प्रेरित करने के लिए, यहाँ एक से कम आदर्श समाधान जो है सबसे अच्छा मैं अब तक के साथ आने में कामयाब रहे है या नहीं:

class IAddObj(object): 
    def __init__(self): 
     self._val = 5 

    def __str__(self): 
     return str(self._val) 

    def __iadd__(self, value): 
     print '__iadd__!' 
     self._val += value 
     return self._val 

class TestObj2(object): 
    def __init__(self): 
     self._x = IAddObj() 

    @property 
    def x(self): 
     return self._x 

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

>>> o = TestObj2() 
>>> print o.x 
5 
>>> o.x = 10 
>>> print o.x 
10 
>>> o.x += 5 
__iadd__! 
>>> print o.x 
15 
>>> print o.x + 5 # doesn't work unless __add__ is also implemented 
TypeError: unsupported operand type(s) for +: 'IAddObj' and 'int' 

बड़ा नुकसान किया जा रहा है, तो आप पूर्ण लागू करने के लिए है कि IAddObj पर संख्यात्मक जादू विधियों के पूरक यदि आप चाहते हैं कि संपत्ति किसी संख्या की तरह व्यवहार करे। IAddObjint से उत्तराधिकारी होने के कारण यह ऑपरेटरों को प्राप्त करने की प्रतीत नहीं होता है।

+0

आप कहते हैं "IAddObj को 'int' से प्राप्त करने के लिए यह ऑपरेटरों को प्राप्त करने की प्रतीत नहीं होता है।" यह बिल्कुल सच नहीं है। समस्या यह है कि यदि आप अन्य सभी ऑपरेटरों को ओवरराइड नहीं करते हैं, तो 'IAddObj (5) + 5' का प्रकार 'int' है, न कि 'IAddObj', क्योंकि इन्स अपरिवर्तनीय हैं, और सभी परिचालन हमेशा नए इंट्स लौटते हैं। हालांकि, मेटाक्लास का उपयोग करके इस तरह वास्तव में एक तरीका है। [यह जवाब देखें] (http://stackoverflow.com/q/10771010/577088)। – senderle

+0

हालांकि, इसके बारे में और सोचते हुए, मेरा मानना ​​है कि ecatmur और muksie समाधान प्रदान करते हैं जो कम जटिल और आपके वास्तविक लक्ष्यों के लिए अधिक उपयुक्त होंगे। – senderle

1

क्यों निम्नलिखित उदाहरण की तरह कुछ नहीं। असल में विचार है कि बार वर्ग को संपत्ति एक्स के लिए संग्रहीत मूल्य सुनिश्चित करना हमेशा एक फू ऑब्जेक्ट होता है।

class Foo(object): 
    def __init__(self, val=0): 
     print 'init' 
     self._val = val 

    def __add__(self, x): 
     print 'add' 
     return Foo(self._val + x) 

    def __iadd__(self, x): 
     print 'iadd' 
     self._val += x 
     return self 

    def __unicode__(self): 
     return unicode(self._val) 

class Bar(object): 
    def __init__(self): 
     self._x = Foo() 

    def getx(self): 
     print 'getx' 
     return self._x 

    def setx(self, val): 
     if not isinstance(val, Foo): 
      val = Foo(val) 
     print 'setx' 
     self._x = val 

    x = property(getx, setx) 

obj = Bar() 
print unicode(obj.x) 
obj.x += 5 
obj.x = obj.x + 6 
print unicode(obj.x) 

संपादित करें: यह दिखाने के लिए विस्तारित उदाहरण है कि इसे संपत्ति के रूप में कैसे उपयोग किया जाए। मैंने पहली बार समस्या को थोड़ा समझा।

4

लाइन में += ऑपरेटर

o.x += 5 

o.x = o.x.__iadd__(5) 

दाएँ हाथ की ओर पर विशेषता देखने के लिए अनुवाद किया है करने के लिए

o.x = IAddProp.__get__(TestObj2.x, o, TestObj2).__iadd__(5) 

के रूप में अनुवाद किया है आप ca n देखें, को पर वापसी मूल्य के पर वापस मूल्य कहा जाता है, इसलिए आपको लौटे ऑब्जेक्ट पर __iadd__() लागू करने की आवश्यकता है।

+0

यह सही नहीं है। या तो 'o.x .__ iadd __ (5) 'कहा जाता है, या यदि' o.x' नहीं है और '__iadd__' विधि है,' o.x = o.x + 5' कहा जाता है। यही है, 'o.x = o.x .__ iadd __ (5)' का कभी भी उपयोग नहीं किया जाता है, क्योंकि '__iadd__' कुछ भी वापस नहीं करता है। –

+0

@MarkLodato कृपया उन्हें चिल्लाने से पहले अपने दावों की पुष्टि करें। यह बिल्कुल जवाब में बुना हुआ है। कोशिश करके देखो। – glglgl

+0

@MarkLodato यहां देखें: http://codepad.org/wbURpQJT यह दिखाता है कि '__iadd __() 'को' + = '(बाईं ओर बाएं हाथ के नाम पर पूरी तरह से नया करने की क्षमता) करने पर कैसे कहा जाता है, और यह भी दिखाता है क्या सूची है .__ iadd __() 'रिटर्न: इसका 'स्वयं'। – glglgl

संबंधित मुद्दे

 संबंधित मुद्दे