Why property works only for objects?

Alex Martelli aleaxit at yahoo.com
Sat Mar 11 22:48:57 CET 2006


Michal Kwiatkowski <ruby at no.spam> wrote:
   ...
> Alex Martelli napisa?(a):
> >>>> 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__.
> 
> It still bugs me. What's the actual procedure when doing attribute
> assignment? I understand it like this:
> 
> obj.attr = value
>  * if instance class has __setattr__, call it
>    * else: if class has an attribute with name "attr" check if it's a
>      descriptor; when it's overriding descriptor, call its __set__
>      method, otherwise raise AttributeError
>      * else: bind "attr" as object attribute

Yes, this is correct.


> I've initialized C.__dict__ as plain dictionary, so it's not a
> descriptor. C also doesn't have __setattr__ method. I'm probably wrong,
> as __dict__ is considered somewhat special, but I can't really
> understand to which degree. Any other attribute I try to bind to object
> will be stored inside object dictionary, without looking up class
> dictionary. __dict__ is special, because it's *the* dictionary that
> stores all references to object's attributes. So, when assigning to
> __dict__ I would expect old dictionary to be simply replaced with this
> one. I don't understand why class attributes has any factor in this.

As I said, it looks to me like you've found a bug here.  __dict__ (like
all names starting and ending in double underscores) is special, in the
sense that Python can do with it whatever it wishes, but there is
neither any documentation nor any reason explaining the behavior you
have observed.

> > C.__dict__ gives you a dictproxy, not a real dict, by the way:
> > 
> >>>> obj.__dict__ is C.__dict__['__dict__']
> > True
> 
> Why is that? I've initialized it as dictionary. When the type was
> changed and why? Is this used anywhere?

That's type(C)'s doing, and as such, perfectly correct: C.__dict__ for
any type C always returns a dictproxy (so that Python, internally,
doesn't _have_ to use a real dict, but rather a structure of slots that
may be much more compact and fast to access).


> > The funny thing is that builtins like var, which should know better,
> > also get fooled...:
> > 
> >>>> vars(obj)
> > {}
> >>>> vars(obj) is C.__dict__['__dict__']
> > True
> 
> Docstring for vars says:
>     With an argument, equivalent to object.__dict__.
> 
> So this behavior simply conforms to the doc.

But the behavior of obj.__dict__={} doesn't.


> > 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__...
> 
> What solution do you propose?

Opening a bug report on the Python bugtracker would maximize the
likelihood that something gets done about this bug.


Alex



More information about the Python-list mailing list