__Getattr__ और __getattribute__ के बीच अंतर को समझना


206

मैं अंतर को समझने के बीच कोशिश कर रहा हूँ __getattr__और __getattribute__, फिर भी, मैं इसे में नाकाम रहने के कर रहा हूँ।

बनाम के बीच स्टैक ओवरफ्लो प्रश्न अंतर का उत्तर कहता है:__getattr____getattribute__

__getattribute__ऑब्जेक्ट पर वास्तविक विशेषताओं को देखने से पहले इसे लागू किया जाता है, और इसलिए इसे सही तरीके से लागू करने के लिए मुश्किल हो सकता है। आप अनंत पुनरावृत्तियों में बहुत आसानी से समाप्त हो सकते हैं।

मुझे बिल्कुल पता नहीं है कि इसका क्या मतलब है।

तो यह कहने पर चला जाता है:

आप लगभग निश्चित रूप से चाहते हैं __getattr__

क्यों?

मैंने पढ़ा है कि यदि __getattribute__विफल रहता है, __getattr__तो कहा जाता है। तो एक ही काम करने के दो अलग-अलग तरीके क्यों हैं? यदि मेरा कोड नई शैली की कक्षाओं को लागू करता है, तो मुझे क्या उपयोग करना चाहिए?

मैं इस प्रश्न को स्पष्ट करने के लिए कुछ कोड उदाहरणों की तलाश कर रहा हूं। मैं अपनी सर्वश्रेष्ठ क्षमता के लिए Googled हूं, लेकिन मुझे जो उत्तर मिले वे समस्या पर पूरी तरह से चर्चा नहीं करते हैं।

यदि कोई दस्तावेज है, तो मैं उसे पढ़ने के लिए तैयार हूं।


2
यदि यह डॉक्स से मदद करता है, तो "इस पद्धति में अनंत पुनरावृत्ति से बचने के लिए, इसके कार्यान्वयन को हमेशा आधार वर्ग विधि को उसी नाम से पुकारना चाहिए, जिसकी किसी भी विशेषता की आवश्यकता हो, उदाहरण के लिए, ऑब्जेक्ट .__ getattribute __ (स्व, नाम)। " [ docs.python.org/2/reference/…
kmonsoor

जवाबों:


306

पहले कुछ मूल बातें।

वस्तुओं के साथ, आपको इसकी विशेषताओं से निपटने की आवश्यकता है। आमतौर पर हम करते हैं instance.attribute। कभी-कभी हमें अधिक नियंत्रण की आवश्यकता होती है (जब हम पहले से विशेषता का नाम नहीं जानते हैं)।

उदाहरण के लिए, instance.attributeबन जाएगा getattr(instance, attribute_name)। इस मॉडल का उपयोग, हम की आपूर्ति के द्वारा विशेषता प्राप्त कर सकते हैं ATTRIBUTE_NAME स्ट्रिंग के रूप।

का उपयोग __getattr__

आप किसी वर्ग को उन विशेषताओं से निपटने का तरीका भी बता सकते हैं जिन्हें वह स्पष्ट रूप से प्रबंधित नहीं करता है और __getattr__विधि के माध्यम से करता है।

जब भी आप पहले से परिभाषित नहीं की गई विशेषता के लिए अनुरोध करते हैं, तो पायथन इस विधि को कॉल करेगा, इसलिए आप इसे परिभाषित कर सकते हैं कि इसके साथ क्या करना है।

एक क्लासिक उपयोग मामला:

class A(dict):
    def __getattr__(self, name):
       return self[name]
a = A()
# Now a.somekey will give a['somekey']

केवेट और उपयोग __getattribute__

अगर आपको इसकी परवाह किए बिना कि यह मौजूद है या नहीं , तो हर विशेषता को पकड़ना __getattribute__चाहिए। अंतर यह है कि __getattr__केवल उन विशेषताओं के लिए बुलाया जाता है जो वास्तव में मौजूद नहीं हैं। यदि आप एक विशेषता को सीधे सेट करते हैं, तो उस विशेषता को संदर्भित करते हुए इसे कॉल किए बिना पुनर्प्राप्त किया जाएगा __getattr__

__getattribute__ हर समय कहा जाता है।


"उदाहरण के लिए, inst.attribute बन जाएगा getattr(instance, attribute_name)।" यह नहीं होना चाहिए __getattribute__(instance, attribute_name)?
मो। अबु नफ़ी इब्ना ज़ाहिद

1
@ Md.AbuNafeeIbnaZahid getattrएक बिल्ट-इन फ़ंक्शन है। getattr(foo, 'bar')के बराबर है foo.bar
wizzwizz4

ध्यान देने योग्य है कि __getattr__केवल यह कहा जाता है अगर यह परिभाषित किया गया है, क्योंकि यह विरासत में नहीं मिला हैobject
joelb

94

__getattribute__ जब भी एक विशेषता पहुंच होती है तो उसे कहा जाता है।

class Foo(object):
    def __init__(self, a):
        self.a = 1

    def __getattribute__(self, attr):
        try:
            return self.__dict__[attr]
        except KeyError:
            return 'default'
f = Foo(1)
f.a

यह अनंत पुनरावृत्ति का कारण बनेगा। यहां अपराधी लाइन है return self.__dict__[attr]। आइए दिखाते हैं (यह सत्य के काफी करीब है) कि सभी विशेषताएँ self.__dict__उनके नाम से संग्रहीत और उपलब्ध हैं। रेखा

f.a

की aविशेषता तक पहुँचने का प्रयास करता है f। यह कॉल करता है f.__getattribute__('a')__getattribute__फिर लोड करने की कोशिश करता है self.__dict____dict__एक विशेषता है self == fऔर इसलिए अजगर कॉल f.__getattribute__('__dict__')जो फिर से विशेषता तक पहुँचने की कोशिश करता है '__dict__'। यह अनंत पुनरावृत्ति है।

अगर __getattr__इसके बजाय इस्तेमाल किया गया था

  1. यह कभी नहीं चला होगा क्योंकि fएक aविशेषता है।
  2. यदि यह चला था, (चलो कहते हैं कि आपने पूछा था f.b) तो इसे खोजने के लिए नहीं बुलाया जाएगा __dict__क्योंकि यह पहले से ही है और __getattr__केवल तब ही लागू किया जाता है जब विशेषता खोजने के अन्य सभी तरीके विफल हो गए हों

उपरोक्त वर्ग का उपयोग करने का 'सही' तरीका __getattribute__है

class Foo(object):
    # Same __init__

    def __getattribute__(self, attr):
        return super(Foo, self).__getattribute__(attr)

super(Foo, self).__getattribute__(attr)__getattribute__वर्तमान ऑब्जेक्ट के लिए 'निकटतम' सुपरक्लास की विधि (औपचारिक रूप से, क्लास के विधि रिज़ॉल्यूशन ऑर्डर, या एमआरओ में अगली कक्षा) को बांधता है selfऔर फिर उसे कॉल करता है और काम करने देता है।

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

यह भी ध्यान देने योग्य है कि आप अनंत पुनरावृत्ति में भाग सकते हैं __getattr__

class Foo(object):
    def __getattr__(self, attr):
        return self.attr

मैं उस एक अभ्यास के रूप में छोड़ दूँगा।


60

मुझे लगता है कि अन्य उत्तरों ने __getattr__और के बीच अंतर को समझाने का एक बड़ा काम किया है __getattribute__, लेकिन एक बात जो स्पष्ट नहीं हो सकती है वह यह है कि आप इसका उपयोग क्यों करना चाहते हैं __getattribute__। इसके बारे __getattribute__में अच्छी बात यह है कि यह अनिवार्य रूप से आपको एक वर्ग तक पहुँचने पर डॉट को ओवरलोड करने की अनुमति देता है। यह आपको यह अनुकूलित करने की अनुमति देता है कि निम्न स्तर पर विशेषताओं को कैसे एक्सेस किया जाता है। उदाहरण के लिए, मान लीजिए कि मैं एक ऐसे वर्ग को परिभाषित करना चाहता हूँ जहाँ सभी विधियाँ जो केवल एक आत्म तर्क लेती हैं उन्हें गुणों के रूप में माना जाता है:

# prop.py
import inspect

class PropClass(object):
    def __getattribute__(self, attr):
        val = super(PropClass, self).__getattribute__(attr)
        if callable(val):
            argcount = len(inspect.getargspec(val).args)
            # Account for self
            if argcount == 1:
                return val()
            else:
                return val
        else:
            return val

और इंटरैक्टिव दुभाषिया से:

>>> import prop
>>> class A(prop.PropClass):
...     def f(self):
...             return 1
... 
>>> a = A()
>>> a.f
1

बेशक यह एक मूर्खतापूर्ण उदाहरण है और आप शायद ऐसा कभी नहीं करना चाहेंगे, लेकिन यह आपको वह शक्ति दिखाता है जो आप ओवरराइडिंग से प्राप्त कर सकते हैं __getattribute__


6

मैं दूसरे की उत्कृष्ट व्याख्या से गुजरा हूँ। हालाँकि, मुझे इस ब्लॉग पायथन मैजिक मेथड्स__getattr__ से एक सरल उत्तर मिला और । सभी निम्नलिखित वहाँ से हैं।

__getattr__जादू की विधि का उपयोग करते हुए , हम उस अपरिहार्य विशेषता को खोज सकते हैं और ऐसा कुछ कर सकते हैं ताकि यह विफल न हो:

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.does_not_exist # 'DOES_NOT_EXIST'
d.what_about_this_one  # 'WHAT_ABOUT_THIS_ONE'

लेकिन अगर विशेषता मौजूद नहीं है, __getattr__तो इसे लागू नहीं किया जाएगा:

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.value = "Python"
print(d.value)  # "Python"

__getattribute__के समान है __getattr__, जो महत्वपूर्ण अंतर के साथ है जो हर किसी के विशेषता देखने __getattribute__को रोक देगा , कोई फर्क नहीं पड़ता कि विशेषता मौजूद है या नहीं।

class Dummy(object):

    def __getattribute__(self, attr):
        return 'YOU SEE ME?'

d = Dummy()
d.value = "Python"
print(d.value)  # "YOU SEE ME?"

उस उदाहरण में, dऑब्जेक्ट का पहले से ही एक विशेषता मान है। लेकिन जब हम इसे एक्सेस करने की कोशिश करते हैं, तो हमें मूल अपेक्षित मूल्य ("पायथन") नहीं मिलता है; हम बस जो भी __getattribute__लौटा रहे हैं। इसका मतलब है कि हमने वस्तुत: मूल्य विशेषता खो दी है; यह "अगम्य" हो गया है।

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