मैं समझने की कोशिश कर रहा हूं कि कब उपयोग करना है __getattr__या नहीं __getattribute__। प्रलेखन का उल्लेख है __getattribute__नई शैली वर्गों के लिए लागू होता है। नई शैली की कक्षाएं क्या हैं?
मैं समझने की कोशिश कर रहा हूं कि कब उपयोग करना है __getattr__या नहीं __getattribute__। प्रलेखन का उल्लेख है __getattribute__नई शैली वर्गों के लिए लागू होता है। नई शैली की कक्षाएं क्या हैं?
जवाबों:
के बीच एक महत्वपूर्ण अंतर यह है __getattr__और __getattribute__वह यह है कि __getattr__केवल अगर विशेषता सामान्य तरीकों से नहीं मिला था शुरू हो जाती है। यह लापता विशेषताओं के लिए एक वापसी को लागू करने के लिए अच्छा है, और शायद दो में से एक है जिसे आप चाहते हैं।
__getattribute__ऑब्जेक्ट पर वास्तविक विशेषताओं को देखने से पहले आह्वान किया जाता है, और इसलिए इसे सही ढंग से लागू करने के लिए मुश्किल हो सकता है। आप अनंत पुनरावृत्तियों में बहुत आसानी से समाप्त हो सकते हैं।
नई शैली की कक्षाएं object, पुरानी शैली की कक्षाओं से प्राप्त होती हैं , जो कि बिना किसी स्पष्ट आधार वर्ग के पायथन 2.x में हैं। लेकिन पुरानी शैली और नई शैली की कक्षाओं के बीच का अंतर महत्वपूर्ण नहीं है, जब आपस में चुनते हैं __getattr__और __getattribute__।
आप लगभग निश्चित रूप से चाहते हैं __getattr__।
__getattribute__हर पहुंच के लिए बुलाया जाएगा, और __getattr__उस समय के लिए कॉल किया जाएगा जिसने __getattribute__उठाया AttributeError। सिर्फ एक में ही क्यों न रखें?
__getattribute__।
objec.__getattribute__आक्रमण myclass.__getattr__।
आओ हम दोनों __getattr__और __getattribute__जादू विधियों के कुछ सरल उदाहरण देखें ।
__getattr____getattr__जब भी आप किसी विशेषता का अनुरोध करते हैं, जिसे आप पहले से परिभाषित नहीं करते हैं, तो पायथन विधि को कॉल करेगा । निम्नलिखित उदाहरण में मेरे वर्ग गणना की कोई __getattr__विधि नहीं है। अब मुख्य में जब मैं दोनों का उपयोग करने की कोशिश करता हूं obj1.myminऔर obj1.mymaxसब कुछ ठीक काम करता है। लेकिन जब मैं obj1.mycurrentविशेषता तक पहुंचने की कोशिश करता हूं - पायथन मुझे देता हैAttributeError: 'Count' object has no attribute 'mycurrent'
class Count():
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent) --> AttributeError: 'Count' object has no attribute 'mycurrent'
अब मेरी कक्षा गणना में __getattr__विधि है। अब जब मैं obj1.mycurrentविशेषता तक पहुंचने की कोशिश करता हूं - अजगर ने मुझे मेरे __getattr__तरीके से जो भी लागू किया है वह मुझे वापस कर देता है । मेरे उदाहरण में जब भी मैं एक विशेषता को कॉल करने की कोशिश करता हूं जो मौजूद नहीं है, तो अजगर उस विशेषता को बनाता है और इसे पूर्णांक मान 0 पर सेट करता है।
class Count:
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
def __getattr__(self, item):
self.__dict__[item]=0
return 0
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent1)
__getattribute__अब __getattribute__विधि देखते हैं । यदि आपके पास __getattribute__अपनी कक्षा में विधि है, तो अजगर हर विशेषता के लिए इस पद्धति को आमंत्रित करता है, चाहे वह मौजूद हो या न हो। तो हमें __getattribute__विधि की आवश्यकता क्यों है ? एक अच्छा कारण यह है कि आप विशेषताओं तक पहुंच को रोक सकते हैं और उन्हें अधिक सुरक्षित बना सकते हैं जैसा कि निम्नलिखित उदाहरण में दिखाया गया है।
जब भी कोई मेरी विशेषताओं को एक्सेस करने की कोशिश करता है, जो कि 'कर्व' अजगर के विकल्प से शुरू होता है, AttributeErrorअपवाद को जन्म देता है। अन्यथा यह उस विशेषता को लौटाता है।
class Count:
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
self.current=None
def __getattribute__(self, item):
if item.startswith('cur'):
raise AttributeError
return object.__getattribute__(self,item)
# or you can use ---return super().__getattribute__(item)
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)
महत्वपूर्ण: __getattribute__विधि में अनंत पुनरावृत्ति से बचने के लिए , इसके कार्यान्वयन को हमेशा किसी भी विशेषता की आवश्यकता को एक्सेस करने के लिए उसी नाम के साथ बेस क्लास विधि को कॉल करना चाहिए। उदाहरण के लिए: object.__getattribute__(self, name)या super().__getattribute__(item)नहींself.__dict__[item]
यदि आपकी कक्षा में गेटअटर और गेटअट्रीब्यूट मैजिक दोनों विधियाँ हैं तो __getattribute__पहले कहा जाता है। लेकिन यदि अपवाद को __getattribute__उठाता
AttributeErrorहै तो अपवाद को नजरअंदाज __getattr__किया जाएगा और विधि को लागू किया जाएगा। निम्नलिखित उदाहरण देखें:
class Count(object):
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
self.current=None
def __getattr__(self, item):
self.__dict__[item]=0
return 0
def __getattribute__(self, item):
if item.startswith('cur'):
raise AttributeError
return object.__getattribute__(self,item)
# or you can use ---return super().__getattribute__(item)
# note this class subclass object
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)
__getattribute__लेकिन निश्चित रूप से यह नहीं है। क्योंकि आपके उदाहरण प्रति, तुम सब में क्या कर रहे हैं __getattribute__ला रहा है AttributeErrorअपवाद अगर विशेषता में वहाँ नहीं है __dict__वस्तु की; लेकिन आपको वास्तव में इसकी आवश्यकता नहीं है क्योंकि यह डिफ़ॉल्ट कार्यान्वयन है __getattribute__और वास्तव __getattr__में वही है जो आपको एक कमबैक तंत्र के रूप में चाहिए।
currentके उदाहरण पर परिभाषित किया गया है Count(देखें __init__), तो बस ऊपर उठाने AttributeErrorविशेषता वहाँ नहीं है है, तो काफी क्या हो रहा है नहीं है - यह को defers __getattr__के लिए सभी नाम 'CUR' शुरू करने, सहित current, लेकिन यह भी curious, curly...
यह नेड बैचेलेडर की व्याख्या पर आधारित एक उदाहरण मात्र है ।
__getattr__ उदाहरण:
class Foo(object):
def __getattr__(self, attr):
print "looking up", attr
value = 42
self.__dict__[attr] = value
return value
f = Foo()
print f.x
#output >>> looking up x 42
f.x = 3
print f.x
#output >>> 3
print ('__getattr__ sets a default value if undefeined OR __getattr__ to define how to handle attributes that are not found')
और अगर __getattribute__आप के साथ एक ही उदाहरण का उपयोग किया जाता है तो आपको >>> मिलेगाRuntimeError: maximum recursion depth exceeded while calling a Python object
__getattr__()कार्यान्वयन केवल AttributeErrorअमान्य विशेषता नामों के लिए वैध विशेषता नामों का एक निश्चित सेट स्वीकार करते हैं , जिससे सूक्ष्म और कठिन-से-डिबग मुद्दों से बचते हैं । यह उदाहरण बिना शर्त के सभी विशेषता नामों को मान्य मानता है - एक विचित्र (और स्पष्ट रूप से त्रुटि-प्रवण) दुरुपयोग __getattr__()। यदि आप इस उदाहरण में विशेषता निर्माण पर "कुल नियंत्रण" चाहते हैं, तो आप __getattribute__()इसके बजाय चाहते हैं।
defaultdict।
__getattr__ कॉल किया जाएगा । यह एक प्रत्यक्ष उपवर्ग के लिए ठीक है , क्योंकि केवल वही विधियाँ हैं जिनके बारे में आप वास्तव में परवाह करते हैं जादू की विधियाँ हैं जो वैसे भी उदाहरण को अनदेखा करते हैं, लेकिन किसी भी अधिक जटिल विरासत संरचना के लिए, आप पूरी तरह से माता-पिता से कुछ भी प्राप्त करने की क्षमता को हटा देते हैं। object
नई शैली की कक्षाएं object, या किसी अन्य नई शैली वर्ग से विरासत में मिली हैं :
class SomeObject(object):
pass
class SubObject(SomeObject):
pass
पुरानी शैली की कक्षाएं नहीं:
class SomeObject:
pass
यह केवल पायथन 2 पर लागू होता है - पायथन 3 में उपरोक्त सभी नई शैली की कक्षाएं बनाएंगे।
देखें 9. कक्षाएं (पायथन ट्यूटोरियल), न्यूक्लास वीक्स्लैकक्लास और पायथन में पुरानी शैली और नई शैली वर्गों के बीच क्या अंतर है? ब्योरा हेतु।
नई शैली की कक्षाएं वे हैं जो "वस्तु" (सीधे या अप्रत्यक्ष रूप से) को उपवर्गित करती हैं। उनके पास __new__इसके अलावा एक वर्ग विधि है__init__ और कुछ अधिक तर्कसंगत निम्न-स्तरीय व्यवहार है।
आमतौर पर, आप ओवरराइड करना चाहेंगे __getattr__ (यदि आप या तो ओवरराइड कर रहे हैं), अन्यथा आपके पास अपने तरीकों के भीतर "सेल्फू" सिंटैक्स का समर्थन करने का कठिन समय होगा।
अतिरिक्त जानकारी: http://www.devx.com/opensource/Article/31482/0/page/4
बेज़ले और जोन्स पीसीबी के माध्यम से पढ़ने में, मैं एक स्पष्ट और व्यावहारिक उपयोग के मामले पर ठोकर खाई है __getattr__ है जो ओपी के प्रश्न के "जब" भाग का जवाब देने में मदद करता है। पुस्तक से:
" __getattr__()विधि विशेषता लुकअप के लिए कैच-ऑल की तरह है। यह एक विधि है जिसे कॉल किया जाता है यदि कोड मौजूद विशेषता को एक्सेस करने का प्रयास करता है।" हम इसे उपरोक्त उत्तरों से जानते हैं, लेकिन पीसीबी नुस्खा 8.15 में, इस कार्यक्षमता का उपयोग डेलिगेशन डिज़ाइन पैटर्न को लागू करने के लिए किया जाता है । यदि ऑब्जेक्ट ए में एक विशेषता ऑब्जेक्ट बी है जो ऑब्जेक्ट ए में ऑब्जेक्ट बी के सभी तरीकों को फिर से परिभाषित करने के बजाय ऑब्जेक्ट ए को प्रतिनिधि बनाना चाहता है, तो ऑब्जेक्ट बी के तरीकों को कॉल करने के लिए केवल __getattr__()निम्न तरीकों को परिभाषित करें :
def __getattr__(self, name):
return getattr(self._b, name)
जहाँ _b ऑब्जेक्ट A की विशेषता का नाम है, जो कि ऑब्जेक्ट B है। जब ऑब्जेक्ट B पर परिभाषित विधि को ऑब्जेक्ट A पर बुलाया जाता है, तो __getattr__विधि लुकअप चेन के अंत में आ जाएगी। यह कोड क्लीनर भी बना देगा, क्योंकि आपके पास किसी अन्य वस्तु को प्रस्तुत करने के लिए परिभाषित तरीकों की सूची नहीं है।