Attribute reference design

Cédric Lucantis omer at no-log.org
Wed Jul 2 06:35:04 EDT 2008


Le Wednesday 02 July 2008 01:17:21 Gary Herron, vous avez écrit :
> chamalulu wrote:
> > On Jul 1, 11:24 pm, "Diez B. Roggisch" <de... at nospam.web.de> wrote:
> >> chamalulu schrieb:
> >>> Hello.
> >>> I think I'm aware of how attribute access is resolved in python. When
> >>> referencing a class instance attribute which is not defined in the
> >>> scope of the instance, Python looks for a class attribute with the
> >>> same name. (For assignment or deletion this is not the case,
> >>> thankfully.)
> >>> I've been trying to understand why? What is the reason behind, or
> >>> practical purpose of, this design decision? Anyone, please enlighten
> >>> me.
> >>
> >> How else would you resolve methods which are of course defined on the
> >> class but invoked through the instance?
> >
> > Yes, of course... You're right.
> > Didn't think of that.
> > Thank you. I'll go stand in the corner. :)
>
> No need.   Also, you can define a class attribute (C++ might call it a
> static attribute) and access it transparently through an instance.
>
> class C:
>   aClassAttribute = 123
>   def __init__(self, ...):
>     ...
>
> c = C()
> ... do something with c.aClassAttribute ...
>

Be very careful with that, as it looks like C++ or similar other OO languages, 
but python handles it in a strange way if you assign a value to such an 
attribute. It took me a long time to understand what happens here:

class Foo (object) :
    bar = 0

foo = Foo()
print '(1) Foo.bar: %d' % Foo.bar
print '(1) foo.bar: %d' % foo.bar

Foo.bar += 1
print '(2) Foo.bar: %d' % Foo.bar
print '(2) foo.bar: %d' % foo.bar

foo.bar += 1
print '(3) Foo.bar: %d' % Foo.bar
print '(3) foo.bar: %d' % foo.bar

here's the output:

(1) Foo.bar: 0
(1) foo.bar: 0
(2) Foo.bar: 1
(2) foo.bar: 1
(3) Foo.bar: 1 # hey dude, where is my bar ?
(3) foo.bar: 2

In the third case, you might expect foo.bar += 1 to just increment Foo.bar, 
but actually it doesn't. I first thought it was a bug, but it's not. When you 
write foo.bar += 1 (equivalent to foo.bar = foo.bar + 1), python first looks 
for a bar attribute, finds it in the class members, and then creates an 
instance member with the result. Things would be different with a mutable 
type implementing the += operator.

I discovered this in a middle of a project and it was hard to track all these 
assignments in my code to correct them, so I'd suggest to always access class 
members through the class instead of the instance, unless you have no choice 
or know exactly what you are doing.

-- 
Cédric Lucantis



More information about the Python-list mailing list