निम्नलिखित कोड पर एक नज़र डालें: कुछ मूलभूत मूल्यों से युक्त अपने स्वयं के शब्दकोश के साथ प्रत्येकपायथन में सुपरक्लास के क्लास गुणों का उपयोग कैसे करें?
class A(object):
defaults = {'a': 1}
def __getattr__(self, name):
print('A.__getattr__')
return self.get_default(name)
@classmethod
def get_default(cls, name):
# some debug output
print('A.get_default({}) - {}'.format(name, cls))
try:
print(super(cls, cls).defaults) # as expected
except AttributeError: #except for the base object class, of course
pass
# the actual function body
try:
return cls.defaults[name]
except KeyError:
return super(cls, cls).get_default(name) # infinite recursion
#return cls.__mro__[1].get_default(name) # this works, though
class B(A):
defaults = {'b': 2}
class C(B):
defaults = {'c': 3}
c = C()
print('c.a =', c.a)
मैं वर्गों के एक पदानुक्रम है। यदि किसी वर्ग के किसी उदाहरण में कोई विशेष विशेषता नहीं है, तो इसके लिए डिफ़ॉल्ट मान इसके बदले वापस किया जाना चाहिए। यदि विशेषता के लिए कोई डिफ़ॉल्ट मान वर्तमान वर्ग के defaults
शब्दकोश में निहित नहीं है, तो सुपरक्लास के defaults
शब्दकोश को खोजा जाना चाहिए।
मैं रिकर्सिव क्लास विधि get_default
का उपयोग करके इसे कार्यान्वित करने की कोशिश कर रहा हूं। दुर्भाग्यवश, कार्यक्रम एक अनंत रिकर्सन में फंस गया है। super()
की मेरी समझ में कमी है। __mro__
तक पहुंचकर, मैं इसे ठीक से काम करने के लिए प्राप्त कर सकता हूं, लेकिन मुझे यकीन नहीं है कि यह एक उचित समाधान है।
मुझे लगता है कि उत्तर this article में कहीं है, लेकिन मैं इसे अभी तक नहीं ढूंढ पाया। शायद मुझे मेटाक्लास का उपयोग करने का सहारा लेना चाहिए?
संपादित करें: मेरे आवेदन में, __getattr__
पहले self.base
चेक करता है। यदि यह None
नहीं है, तो वहां से विशेषता प्राप्त की जानी चाहिए। केवल दूसरे मामले में, एक डिफ़ॉल्ट मान वापस किया जाना चाहिए। मैं शायद __getattribute__
ओवरराइड कर सकता था। क्या यह बेहतर समाधान होगा?
संपादित करें 2: नीचे कार्यक्षमता का विस्तारित उदाहरण है जिसे मैं ढूंढ रहा हूं। वर्तमान में इसे __mro__
(यूनूटू के पहले सुझाव, मेरी मूल रिकर्सिव विधि के विपरीत) का उपयोग करके कार्यान्वित किया गया है। जब तक कि कोई अधिक सुरुचिपूर्ण समाधान का सुझाव नहीं दे सकता, मैं इस कार्यान्वयन का उपयोग करके खुश हूं। मै उम्मीद करता हू कि यह बातें अब साफ है।
class A(object):
defaults = {'a': 1}
def __init__(self, name, base=None):
self.name = name
self.base = base
def __repr__(self):
return self.name
def __getattr__(self, name):
print(" '{}' attribute not present in '{}'".format(name, self))
if self.base is not None:
print(" getting '{}' from base ({})".format(name, self.base))
return getattr(self.base, name)
else:
print(" base = None; returning default value")
return self.get_default(name)
def get_default(self, name):
for cls in self.__class__.__mro__:
try:
return cls.defaults[name]
except KeyError:
pass
raise KeyError
class B(A):
defaults = {'b': 2}
class C(B):
defaults = {'c': 3}
c1 = C('c1')
c1.b = 55
print('c1.a = ...'); print(' ...', c1.a) # 1
print(); print('c1.b = ...'); print(' ...', c1.b) # 55
print(); print('c1.c = ...'); print(' ...', c1.c) # 3
c2 = C('c2', base=c1)
c2.c = 99
print(); print('c2.a = ...'); print(' ...', c2.a) # 1
print(); print('c2.b = ...'); print(' ...', c2.b) # 55
print(); print('c2.c = ...'); print(' ...', c2.c) # 99
उत्पादन:
c1.a = ...
'a' attribute not present in 'c1'
base = None; returning default value
... 1
c1.b = ...
... 55
c1.c = ...
'c' attribute not present in 'c1'
base = None; returning default value
... 3
c2.a = ...
'a' attribute not present in 'c2'
getting 'a' from base (c1)
'a' attribute not present in 'c1'
base = None; returning default value
... 1
c2.b = ...
'b' attribute not present in 'c2'
getting 'b' from base (c1)
... 55
c2.c = ...
... 99
शब्दकोश 'डिफ़ॉल्ट' शब्द का उपयोग करने के बजाय डिफ़ॉल्ट रूप से कक्षा नामस्थान में डिफ़ॉल्ट को रखने के बारे में कैसे? इससे कोई जादू अनावश्यक हो जाएगा - यह सिर्फ काम करेगा। –
@ स्वेन मुझे पता था कि मुझे इसका उल्लेख करना चाहिए था :) मेरे आवेदन में, '__getattr__' पहले एक और विशेषता (आधार) की जांच कर रहा है। केवल अगर अन्य विशेषता कोई नहीं है, तो डिफ़ॉल्ट मान वापस किया जाना चाहिए। अन्यथा, विशेषता को आधार में देखने की आवश्यकता है। –
हाँ, इस तरह पाइथन में उदाहरण/वर्ग विशेषताएँ काम करती हैं। :) टोनी के जवाब की जांच करें। अफैक उसका कोड बिल्कुल आपके जैसा ही करेगा। –