Yes; assigning to self.attr in a method (such as __init__) will set that
attribute on the instance, but assigning in the class definition will set
that attribute on the class.
Unless it happens to be defined in the class as a property, in which case that
will be triggered ;-) (BTW, you can use that to good effect in an __init__ or
other method to access a property consistently from everywhere. See example, where
the __init__ accesses the self.prop both ways.
Descriptors (such as properties) need to be set on a class to work their
magic. Instances don't check their attributes for __get__/__set__/__del__
magic methods when accessing them, but classes do.
(This question pops up fairly regularly, and it's not obvious to new users
what's going on... perhaps there should be a FAQ entry about why
per-instance properties don't work?)
You can program a normal property to delegate to instance-specific stuff though, so you
could fake it pretty well if you put your mind to it ;-) The question would be WTHeck you
were trying to do with that kind of design. Ok, we won't break our toys, but we can mess
with them a little to see how they work, e.g.,
... def getprop(self):
... instprop = vars(self).get('prop')
... if instprop: return instprop.fget(self)
... return '%r from getprop'%self._prop
... def setprop(self, v): self._prop=v
... prop = property(getprop, setprop)
... def __init__(self):
... self.prop = '<initial prop value>' # note that this goes via setprop to self._prop
... def instgetprop(self): return '%r from instgetprop'%self._prop
... self.__dict__['prop'] = property(instgetprop) # self.prop would trigger setprop
... "'<initial prop value>' from instgetprop"
Note that the above is deferring to the instance-attribute-defined prop
'123 from instgetprop'
.... still doing it. Now we'll get rid of the instance attribute named prop
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: can't delete attribute
That exception was because the property intercepts get set and del, and we didn't
define the latter property function.
>>> del foo.__dict__['prop'] # this way doesn't trigger class-defined prop
Ok, now to access prop without the instance attribute, so the real prop (which always
gets control) doesn't see anything to defer to:
'123 from getprop'
QED
'456 from getprop'
Now if we re-establish the instance prop by re-executing __init__:
We get the delegated effect (that we programmed the real prop to do) again
'789 from instgetprop'
You could do much more generalized stuff along the same lines, intercepting any attribute
name and checking for an "instance property" also. Only your imagination (and possibly backlash
from your code maintenance heirs ;-) sets the limits.
This sort of stuff is not recommended for ordinary use, but it's nice to know you can do
about anything you want with Python if you have a real need.
However, most such "needs" are probably mistaken ;-)
Regards,
Bengt Richter