Accessing An Object's Attribute Inside __setattr__
Solution 1:
Because inside the __init__
it is trying to set blub
which calls __setattr__
; and it does not set anything but tries to access (and print) blub
, finds nothing and raises the error. Check this:
>>> classTest2(object):
def__init__(self):
print"__init__ called"
self.blub = 'hi2'print"blub was set"def__setattr__(self, name, value):
print"__setattr__ called"print self.blub
>>> Test2()
__init__ called
__setattr__ called
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
Test2()
File "<pyshell#9>", line 4, in __init__
self.blub = 'hi2'
File "<pyshell#9>", line 9, in __setattr__
print self.blub
AttributeError: 'Test2'object has no attribute 'blub'>>>
Solution 2:
OP, you haven't told us the whole story. You did not just run code like this:
TestX().bip = 'bap'
You ran code like this:
try:
TestX().bip = 'bap'
except Exceptionas ex:
print ex
There's a big difference. Why, you ask? Well, your output seems on first glance to indicate that Test6
works, and several comments and answers assumed that it did. Why does it appear to work? Reading the code, there's no way it should work. A closer inspection of the source code reveals that if it had worked, it should have printed hi6
, not 'blub'
.
I put a breakpoint at the print ex
line in pdb
to examine the exception:
(Pdb) ex
KeyError('blub',)
(Pdb) print ex
'blub'
For some reason print ex
does not print KeyError: blub
like you'd expect, but just 'blub'
, which was why Test6
appeared to work.
So we've cleared that up. In the future, please do not leave out code like this because it might be important.
All the other answers correctly point out that you have not set the attribute you're attempting to print, and that this is your problem. The answer you had accepted previously, before you accepted this answer istead, prescribed the following solution:
def__setattr__(self, name, value):
self.__dict__[name] = value
print self.__dict__[name]
While this solution does indeed work, it is not good design. This is because you might want to change the base class at some point, and that base class might might have important side effects when setting and/or getting attributes, or it might not store the attributes in self.__dict__
at all! It is better design to avoid messing around with __dict__
.
The correct solution is to invoke the parent __setattr__
method, and this was suggested by at least one other answer, though with the wrong syntax for python 2.x. Here's how I'd do it:
def__setattr__(self, name, value):
super(Test6, self).__setattr__(name, value)
printgetattr(self, name)
As you see I'm using getattr
instead of __dict__
to look up attributes dynamically. Unlike using __dict__
directly, this will call self.__getattr__
or self.__getattribute__
, as appropriate.
Solution 3:
__setattr__
works on the class, so when you're over-riding - you need to make it actually set the attribute... otherwise, it'll never exist... eg:
object.__setattr__(self, name, value)
So, in your __init__
, when you do self.blub = 'hi'
that's in effect a no-op.
Solution 4:
You never actually set the attribute in your __setattr__
so of course the object doesn't have it.
def__setattr__(self, name, value):
self.name = value
# this doesn't work, since it calls itself (the __setattr__)def__setattr__(self, name, value):
super().__setattr__(name, value)
# call the default implementation directly in Py 3.xdef__setattr__(self, name, value):
super(TestX, self).__setattr__(name, value) # for Python 2.x
Of course doing this alone is good for nothing, you usually want to add some functionality oround this like some condition, debug printing, caching or whatever you need.
Solution 5:
printself.__dict__['blub']
Prints out blub
which is correct. You have to set the new value first, because python won't do that for you, like that:
def__setattr__(self, name, value):
self.__dict__[name] = value
print self.__dict__[name]
Then test6.blub = 'test'
should print out test
Edit:
As suggested by @Lauritz you can also use
def__setattr__(self, name, value):
super(Test6, self).__setattr__(name, value)
print self.__dict__[name]
Which invokes the parent function, so if you superclass has already a __setattr__
function it won't get overridden.
Post a Comment for "Accessing An Object's Attribute Inside __setattr__"