मैं डिफ़ॉल्ट व्यवहार को तोड़े बिना पायथन में __getattr__ को कैसे ओवरराइड करूं?


185

मैं __getattr__कुछ फैंसी करने के लिए एक वर्ग पर विधि को ओवरराइड करना चाहता हूं, लेकिन मैं डिफ़ॉल्ट व्यवहार को तोड़ना नहीं चाहता हूं।

ऐसा करने का सही तरीका क्या है?


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

जवाबों:


268

ओवरराइडिंग __getattr__ठीक होना चाहिए - __getattr__केवल एक अंतिम उपाय के रूप में कहा जाता है अर्थात यदि नाम से मेल खाने वाले उदाहरण में कोई विशेषता नहीं है। उदाहरण के लिए, यदि आप पहुंचते हैं foo.bar, तो __getattr__केवल तभी कॉल किया जाएगा जब fooकोई विशेषता नहीं है bar। यदि विशेषता वह है जिसे आप संभालना नहीं चाहते, तो बढ़ाएँ AttributeError:

class Foo(object):
    def __getattr__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            raise AttributeError

हालांकि, इसके विपरीत __getattr__, __getattribute__पहले कहा जाएगा (केवल नई शैली की कक्षाओं के लिए काम करता है अर्थात जो ऑब्जेक्ट से विरासत में मिलते हैं)। इस स्थिति में, आप डिफ़ॉल्ट व्यवहार को संरक्षित कर सकते हैं जैसे:

class Foo(object):
    def __getattribute__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            return object.__getattribute__(self, name)

अधिक के लिए अजगर डॉक्स देखें ।


बाह, आपके संपादन में वही बात है जो मैं अपने उत्तर में दिखा रहा था, +1।

12
कूल, पायथन को सुपर-इन कॉलिंग पसंद नहीं है __getattr__- किसी भी विचार को क्या करना है? ( AttributeError: 'super' object has no attribute '__getattr__')
गतोतिग्रादो

1
आपके कोड को देखे बिना यह बताना मुश्किल है, लेकिन ऐसा लगता है कि आपका कोई भी सुपरक्लेसेस गेटअटर को परिभाषित नहीं करता है
कॉलिन vH

यह हैसट्रैड के साथ भी काम करता है क्योंकि: "इसे गेटैट्र (ऑब्जेक्ट, नाम) कहकर लागू किया जाता है और यह देखते हुए कि यह अपवाद उठाता है या नहीं।" docs.python.org/2/library/functions.html#hasattr
ShaBANG

1
-1 यह डिफ़ॉल्ट व्यवहार को संशोधित करता है। अब आपके पास AttributeErrorअपवाद आर्ग में विशेषता के संदर्भ के बिना है।
विम

34
class A(object):
    def __init__(self):
        self.a = 42

    def __getattr__(self, attr):
        if attr in ["b", "c"]:
            return 42
        raise AttributeError("%r object has no attribute %r" %
                             (self.__class__.__name__, attr))

>>> a = A()
>>> a.a
42
>>> a.b
42
>>> a.missing
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __getattr__
AttributeError: 'A' object has no attribute 'missing'
>>> hasattr(a, "b")
True
>>> hasattr(a, "missing")
False

इसके लिए धन्यवाद। बस यह सुनिश्चित करना चाहता था कि स्रोत में चारों ओर खुदाई किए बिना मेरे पास डिफ़ॉल्ट संदेश सही था।
शाऊनफुमो

4
मुझे लगता है कि कक्षा के ओवरराइड self.__class__.__name__होने के बजाय इसका उपयोग किया जाना चाहिएself.__class____repr__
माइकल स्कॉट कथबर्ट

3
यह स्वीकार किए गए उत्तर से बेहतर है, लेकिन यह अच्छा होगा कि कोड को फिर से लिखना न पड़े और संभावित रूप से अपस्ट्रीम बदलावों को याद रखना चाहिए ताकि भविष्य में अपवाद वस्तु में जोड़ा गया संशोधित या अतिरिक्त संदर्भ जुड़ जाए।
wim

13

माइकल उत्तर का विस्तार करने के लिए, यदि आप का उपयोग करके डिफ़ॉल्ट व्यवहार बनाए रखना चाहते हैं, तो आप __getattr__ऐसा कर सकते हैं:

class Foo(object):
    def __getattr__(self, name):
        if name == 'something':
            return 42

        # Default behaviour
        return self.__getattribute__(name)

अब अपवाद संदेश अधिक वर्णनात्मक है:

>>> foo.something
42
>>> foo.error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __getattr__
AttributeError: 'Foo' object has no attribute 'error'

2
@ fed.pavlo क्या आपको यकीन है? शायद आप मिश्रित __getattr__और __getattribute__?
जोस लुइस

मेरी गलती। मैं स्वयं से अलग विधि से कॉल करने से चूक गया। ;
खिलाया गया।पावलो

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