python - क्या पाइथन असाइनमेंट को अधिभारित करना संभव है?




class methods (6)

क्या कोई जादू विधि है जो असाइनमेंट ऑपरेटर को अधिभारित कर सकती है, जैसे __assign__(self, new_value) ?

मैं एक उदाहरण के लिए फिर से बांधना चाहता हूं:

class Protect():
  def __assign__(self, value):
    raise Exception("This is an ex-parrot")

var = Protect()  # once assigned...
var = 1          # this should raise Exception()

क्या यह संभव है? क्या यह पागल है? क्या मुझे दवा पर होना चाहिए?


एक बदसूरत समाधान विनाशक पर फिर से सौंपना है। लेकिन यह कोई असली अधिभार असाइनमेंट नहीं है।

import copy
global a

class MyClass():
    def __init__(self):
            a = 1000
            # ...

    def __del__(self):
            a = copy.copy(self)


a = MyClass()
a = 1

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

हालांकि, क्लास इंस्टेंस में किसी सदस्य को असाइनमेंट को आप ओवरराइड करके नियंत्रित कर सकते हैं .__setattr__()

class MyClass(object):
    def __init__(self, x):
        self.x = x
        self._locked = True
    def __setattr__(self, name, value):
        if self.__dict__.get("_locked", False) and name == "x":
            raise AttributeError("MyClass does not allow assignment to .x member")
        self.__dict__[name] = value

>>> m = MyClass(3)
>>> m.x
3
>>> m.x = 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in __setattr__
AttributeError: MyClass does not allow assignment to .x member

ध्यान दें कि एक सदस्य चर है, _locked , यह नियंत्रित करता है कि असाइनमेंट की अनुमति है या नहीं। आप मूल्य को अपडेट करने के लिए इसे अनलॉक कर सकते हैं।



मुझे नहीं लगता कि यह संभव है। जिस तरह से मैं इसे देखता हूं, एक चर के लिए असाइनमेंट उस ऑब्जेक्ट को कुछ भी नहीं करता है जिसे पहले संदर्भित किया गया था: यह केवल वैरिएबल "पॉइंट" को एक अलग ऑब्जेक्ट पर है।

In [3]: class My():
   ...:     def __init__(self, id):
   ...:         self.id=id
   ...: 

In [4]: a = My(1)

In [5]: b = a

In [6]: a = 1

In [7]: b
Out[7]: <__main__.My instance at 0xb689d14c>

In [8]: b.id
Out[8]: 1 # the object is unchanged!

हालांकि, आप __setitem__() या __setattr__() विधियों के साथ एक रैपर ऑब्जेक्ट बनाकर वांछित व्यवहार की नकल कर सकते हैं जो अपवाद उठाते हैं, और "अपरिवर्तनीय" सामान को अंदर रखें।


शीर्ष-स्तरीय नामस्थान का उपयोग करना, यह असंभव है। जब आप दौड़ते हैं

`var = 1`

यह वैश्विक शब्दकोश में कुंजी var और मान 1 स्टोर करता है। यह लगभग globals().__setitem__('var', 1) को कॉल करने के बराबर है। समस्या यह है कि आप वैश्विक शब्दकोश को एक चल रही स्क्रिप्ट में प्रतिस्थापित नहीं कर सकते हैं (संभवतः आप ढेर के साथ गड़बड़ कर सकते हैं, लेकिन यह एक अच्छा विचार नहीं है)। हालांकि आप द्वितीयक नेमस्पेस में कोड निष्पादित कर सकते हैं, और इसके ग्लोबल्स के लिए एक कस्टम शब्दकोश प्रदान कर सकते हैं।

class myglobals(dict):
    def __setitem__(self, key, value):
        if key=='val':
            raise TypeError()
        dict.__setitem__(self, key, value)

myg = myglobals()
dict.__setitem__(myg, 'val', 'protected')

import code
code.InteractiveConsole(locals=myg).interact()

इससे एक आरईपीएल आग लग जाएगी जो लगभग सामान्य रूप से संचालित होती है, लेकिन वेरिएबल val सेट करने के किसी भी प्रयास से इंकार कर देती है। आप execfile(filename, myg) भी उपयोग कर सकते हैं। ध्यान दें कि यह दुर्भावनापूर्ण कोड से सुरक्षा नहीं करता है।


हां, यह संभव है, आप संशोधित __assign__ माध्यम से __assign__ को संभाल सकते हैं।

pip install assign

इसके साथ परीक्षण करें:

class T():
    def __assign__(self, v):
        print('called with %s' % v)
b = T()
c = b

तुम्हे मिल जाएगा

>>> import magic
>>> import test
called with c

प्रोजेक्ट https://github.com/RyanKung/assign और सरल गीस्ट: https://gist.github.com/RyanKung/4830d6c8474e6bcefa4edd13f122b4df





magic-methods