My class has a dict, for example:
class MyClass(object):
def __init__(self):
self.data = {\'a\': \'v1\', \'b\': \'v2\'}
Then I
You can initialize your class dictionary through the constructor:
def __init__(self,**data):
And call it as follows:
f = MyClass(**{'a': 'v1', 'b': 'v2'})
All of the instance attributes being accessed (read) in __setattr__, need to be declared using its parent (super) method, only once:
super().__setattr__('NewVarName1', InitialValue)
Or
super().__setattr__('data', dict())
Thereafter, they can be accessed or assigned to in the usual manner:
self.data = data
And instance attributes not being accessed in __setattr__, can be declared in the usual manner:
self.x = 1
The overridden __setattr__ method must now call the parent method inside itself, for new variables to be declared:
super().__setattr__(key,value)
A complete class would look as follows:
class MyClass(object):
def __init__(self, **data):
# The variable self.data is used by method __setattr__
# inside this class, so we will need to declare it
# using the parent __setattr__ method:
super().__setattr__('data', dict())
self.data = data
# These declarations will jump to
# super().__setattr__('data', dict())
# inside method __setattr__ of this class:
self.x = 1
self.y = 2
def __getattr__(self, name):
# This will callback will never be called for instance variables
# that have beed declared before being accessed.
if name in self.data:
# Return a valid dictionary item:
return self.data[name]
else:
# So when an instance variable is being accessed, and
# it has not been declared before, nor is it contained
# in dictionary 'data', an attribute exception needs to
# be raised.
raise AttributeError
def __setattr__(self, key, value):
if key in self.data:
# Assign valid dictionary items here:
self.data[key] = value
else:
# Assign anything else as an instance attribute:
super().__setattr__(key,value)
Test:
f = MyClass(**{'a': 'v1', 'b': 'v2'})
print("f.a = ", f.a)
print("f.b = ", f.b)
print("f.data = ", f.data)
f.a = 'c'
f.d = 'e'
print("f.a = ", f.a)
print("f.b = ", f.b)
print("f.data = ", f.data)
print("f.d = ", f.d)
print("f.x = ", f.x)
print("f.y = ", f.y)
# Should raise attributed Error
print("f.g = ", f.g)
Output:
f.a = v1
f.b = v2
f.data = {'a': 'v1', 'b': 'v2'}
f.a = c
f.b = v2
f.data = {'a': 'c', 'b': 'v2'}
f.d = e
f.x = 1
f.y = 2
Traceback (most recent call last):
File "MyClass.py", line 49, in <module>
print("f.g = ", f.g)
File "MyClass.py", line 25, in __getattr__
raise AttributeError
AttributeError
Late to the party, but found two really good resources that explain this better (IMHO).
As explained here, you should use self.__dict__
to access fields from within __getattr__
, in order to avoid infinite recursion. The example provided is:
def __getattr__(self, attrName): if not self.__dict__.has_key(attrName): value = self.fetchAttr(attrName) # computes the value self.__dict__[attrName] = value return self.__dict__[attrName]
Note: in the second line (above), a more Pythonic way would be (has_key
apparently was even removed in Python 3):
if attrName not in self.__dict__:
The other resource explains that the __getattr__
is invoked only when the attribute is not found in the object, and that hasattr
always returns True
if there is an implementation for __getattr__
. It provides the following example, to demonstrate:
class Test(object): def __init__(self): self.a = 'a' self.b = 'b' def __getattr__(self, name): return 123456 t = Test() print 'object variables: %r' % t.__dict__.keys() #=> object variables: ['a', 'b'] print t.a #=> a print t.b #=> b print t.c #=> 123456 print getattr(t, 'd') #=> 123456 print hasattr(t, 'x') #=> True