Michal Kwiatkowski <[EMAIL PROTECTED]> wrote: > class C(object): > __dict__ = {} > > obj = C() > obj.a = 7 > obj.__dict__ = {} > print object.__getattribute__(obj, '__dict__') > print object.__getattribute__(C, '__dict__') > print obj.a # => 7 !!! > > First print returns "{}" and the second returns > > {'__dict__': {}, > '__module__': '__main__', > '__weakref__': <attribute '__weakref__' of 'C' objects>, > '__doc__': None} > > Neither of them have "a" attribute. How come obj.a doesn't raise an > exception? Where obj.a is kept?
It's easier to trace if you use a unique value rather than 7 ...: >>> class C(object): ... __dict__ = {} ... >>> obj = C() >>> obj.a = object() >>> import gc >>> gc.get_referrers(obj.a) [{'a': <object object at 0x3d438>}] so, at this point, you know that obj.a is kept in a dictionary where it's the only value. That's the dictionary you would USUALLY be able to get to as obj.__dict__, but...: >>> obj.__dict__ {} ...the presence of '__dict__' as an entry in C is confusing the issue, because that's what you get in this case as obj.__dict__. C.__dict__ gives you a dictproxy, not a real dict, by the way: >>> obj.__dict__ is C.__dict__['__dict__'] True The funny thing is that builtins like var, which should know better, also get fooled...: >>> vars(obj) {} >>> vars(obj) is C.__dict__['__dict__'] True ...and so does the assignment to obj.__dict__...: >>> obj.__dict__ = {} >>> gc.get_referrers(obj.a) [{'a': <object object at 0x3d438>, '__dict__': {}}] Now, both obj.a and obj.__dict__ are entries in a dictionary where they're the only two entries -- exactly the dictionary that would NORMALLY be obj.__dict__. I think a fair case can be made that you've found a bug in Python here: the existence of that __dict__ in C's class body is clearly causing unintended anomalies. Fortunately, getattr and friends don't in fact get confused, but vars does, as does assignment to obj.__dict__... Alex -- http://mail.python.org/mailman/listinfo/python-list