Why property works only for objects?

Alex Martelli aleaxit at yahoo.com
Sat Mar 11 15:07:59 EST 2006


Michal Kwiatkowski <ruby at no.spam> 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



More information about the Python-list mailing list