Take a look at the following code:
class A(object):
defaults = {'a': 1}
def __getattr__(self, name):
print('A.__getattr__')
return self.get_default(name)
@classmethod
def get_default(cls, name):
print('A.get_default({}) - {}'.format(name, cls))
try:
print(super(cls, cls).defaults)
except AttributeError:
pass
try:
return cls.defaults[name]
except KeyError:
return super(cls, cls).get_default(name)
class B(A):
defaults = {'b': 2}
class C(B):
defaults = {'c': 3}
c = C()
print('c.a =', c.a)
I have a class hierarchy, each with its own dictionary containing some default values. If the class instance does not have a specific attribute, you should return the default value instead. If the default value for the attribute is not contained in the current class dictionary defaults, look for the superclass dictionary defaults.
I am trying to implement this using a recursive class method get_default. Unfortunately, the program is stuck in infinite recursion. My understanding is super()clearly absent. Having accessed __mro__, I can make it work properly, but I'm not sure if this is the right solution.
, - , . , ?
edit: __getattr__ self.base. None, . . , __getattribute__. ?
edit 2: , . __mro__ (unutbu , ). - , . , .
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)
print(); print('c1.b = ...'); print(' ...', c1.b)
print(); print('c1.c = ...'); print(' ...', c1.c)
c2 = C('c2', base=c1)
c2.c = 99
print(); print('c2.a = ...'); print(' ...', c2.a)
print(); print('c2.b = ...'); print(' ...', c2.b)
print(); print('c2.c = ...'); print(' ...', c2.c)
:
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