2012-11-24 3 views
17

में अनंत लूप से परहेज करना अनंत लूप से बचने के लिए विधि __getattribute__ को ध्यान से लिखा जाना चाहिए। उदाहरण के लिए:पायथन: __getattribute__

class A: 
    def __init__(self): 
     self.x = 100 

    def __getattribute__(self, x): 
     return self.x 

>>> a = A() 
>>> a.x # infinite looop 
RuntimeError: maximum recursion depth exceeded while calling a Python object 


class B: 
    def __init__(self): 
     self.x = 100 

    def __getattribute__(self, x): 
     return self.__dict__[x] 

>>> b = B() 
>>> b.x # infinite looop 
RuntimeError: maximum recursion depth exceeded while calling a Python object 

इसलिए हम इस तरह से विधि लिखने के लिए की जरूरत है:

class C: 
    def __init__(self): 
     self.x = 100 

    def __getattribute__(self, x): 
     # 1. error 
     # AttributeError: type object 'object' has no attribute '__getattr__' 
     # return object.__getattr__(self, x) 

     # 2. works 
     return object.__getattribute__(self, x) 

     # 3. works too 
     # return super().__getattribute__(x) 

मेरा प्रश्न क्यों object.__getattribute__ विधि काम करता है? object से __getattribute__ विधि प्राप्त होती है? और यदि object में कोई __getattribute__ नहीं है, तो हम कक्षा C पर एक ही विधि को कॉल कर रहे हैं लेकिन सुपर क्लास के माध्यम से। फिर, सुपर क्लास के माध्यम से विधि को कॉल करने के परिणामस्वरूप अनंत लूप नहीं होता है?

+2

क्या आप वाकई '__getattribute__' की आवश्यकता है और '__getattr__' नहीं चाहते हैं? –

+4

हां, मैं हूं, क्योंकि मुझे अपनी कक्षा में सभी विशेषताएं लाने की आवश्यकता है। लेकिन अगर मैं नहीं करता, तब भी मैं पूरी जानकारी जानना चाहता हूं कि ऐसा क्यों है। – treecoder

+1

ठीक है, या तो आपको * सभी * विशेषता पहुंच को अवरुद्ध करना होगा या आप नहीं :-) –

उत्तर

21

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

यह सही नहीं है। जब पाइथन उदाहरणों पर विशेषताओं को देखता है, __getattribute__ सभी विशेषता पहुंच के लिए मुख्य प्रविष्टि है, और object डिफ़ॉल्ट कार्यान्वयन प्रदान करता है। आपका कार्यान्वयन ओवरराइडिंग मूल है, और यदि आपका कार्यान्वयन गुणों को वापस करने का कोई वैकल्पिक माध्यम प्रदान नहीं करता है तो यह विफल हो जाता है। आप उस विधि में विशेषता पहुंच का उपयोग नहीं कर सकते हैं, क्योंकि सभी विशेषताएँ उदाहरण (self) तक पहुंच को type(self).__getattribute__(self, attr) के माध्यम से फिर से प्रसारित किया जाता है।

इसके आसपास का सबसे अच्छा तरीका ओवरराइड मूल को फिर से कॉल करके है। वह जगह है जहां super(C, self).__getattribute__(attr) आता है; आप कक्षा के संकल्प आदेश में अगली कक्षा को आपके लिए विशेषता पहुंच का ख्याल रखने के लिए कह रहे हैं।

वैकल्पिक रूप से, आप अनबाउंड object.__getattribute__() विधि सीधे कॉल कर सकते हैं। इस विधि का सी कार्यान्वयन विशेषता पहुंच के लिए अंतिम स्टॉप है (इसकी __dict__ तक सीधे पहुंच है और इस प्रकार समान सीमाओं तक सीमित नहीं है)।

ध्यान दें कि super() एक प्रॉक्सी ऑब्जेक्ट देता है जो विधि-समाधान आदेशित बेस क्लास में जो भी तरीका पा सकता है उसे देखेगा। यदि ऐसी कोई विधि मौजूद नहीं है, तो यह एक विशेषता त्रुटि के साथ विफल हो जाएगी। यह कभी भी मूल विधि को कॉल करेगा। इस प्रकार Foo.bar()super(Foo, self).bar देख रहे हैं या तो बेस-क्लास कार्यान्वयन या एक विशेषता त्रुटि होगी, कभीFoo.bar स्वयं ही नहीं होगा।

8

जब आप ऐसा करते:

return object.__getattribute__(self, x) 

आप एक विशेष समारोह बुला रहे हैं - एक वस्तु वर्ग में परिभाषित किया गया है, और नहीं एक एक में परिभाषित किया गया है, तो वहाँ कोई प्रत्यावर्तन है।

जब आप ऐसा करते:

return self.x 

आप दे रहे हैं अजगर चुनें जो कॉल करने के लिए कार्य करते हैं, और यह एक से एक कहता है, और आप एक अनंत प्रत्यावर्तन की है।

+0

' ऑब्जेक्ट 'वर्ग पर कोई ऐसा फ़ंक्शन परिभाषित नहीं किया गया है। यदि वहां कोई फ़ंक्शन परिभाषित किया गया था, तो 'ऑब्जेक्ट' भी '__getattr__' को परिभाषित करेगा (जो, जैसा कि # 1 त्रुटि दिखाता है)। तो, फिर ऑब्जेक्ट केवल '__getattribute__' विधि को परिभाषित क्यों करेगा? – treecoder

+1

@greengit: यह क्यों नहीं होगा? मैं 'ऑब्जेक्ट' ऑब्जेक्ट्स के '<स्लॉट रैपर' __getattribute__ 'को देखता हूं>' जब मैं 'ऑब्जेक्ट एक्सेस करता हूं .__ getattribute__'। –

+0

तो आप कह रहे हैं कि 'ऑब्जेक्ट' केवल '__getattribte__' को परिभाषित करता है और '__getattr__' नहीं? जहां तक ​​मुझे पता है, इन सभी विधियों के 'ऑब्जेक्ट' वर्ग का कार्यान्वयन नो-ऑप नहीं है। अगर मैं कहीं गलत हूं तो मुझे सही करो। – treecoder

2

लिखें इसे इस तरह (वस्तु से सी inherits):

class C(object): 
    def __init__(self): 
     self.x = 100 

    def __getattribute__(self, x): 
     return object.__getattribute__(self, x) 

अब आप देख क्यों वस्तु .__ getAttribute __ (स्वयं, एक्स) काम करता है - आप पैरेंट ऑब्जेक्ट बुला रहे हैं।