Adding attributes stored in a list to a class dynamically.

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Mon Sep 3 09:34:59 EDT 2007


On Mon, 03 Sep 2007 04:37:54 +0000, Brian Munroe wrote:

> On Sep 2, 3:33 pm, Steven D'Aprano <st... at REMOVE-THIS-
> cybersource.com.au> wrote:
> 
> 
>> In a nutshell, like all double-underscore methods, __setattr__ are for
>> overriding behaviour in your own classes. With very few exceptions, you
>> shouldn't need to directly call double-underscore methods (although you
>> often may _write_ double-underscore methods).
>>
>>
> I think I understand.  You are saying that if I wanted to override the
> normal behavior when doing something like
> 
>     p1.firstName = "Brian"
> 
> then I'd override __setattr__()?
> 
> But if I am doing something like creating dynamic attributes, the more
> 'correct' way is to use setattr?  Even though they both appear to do the
> same thing, the more Pythonic way is to never directly call magic
> methods (if you can help it)?


No, they don't do the same thing.

The normal way of accessing an object attribute is with the dot operator:

obj.name

Behind the scenes, Python does a whole lot of magic to make that work. 
Under *normal* circumstances, when you write "obj.name" Python looks for 
an attribute called "name", and returns whatever it finds. The *details* 
of the lookup process itself can be as simple as "look in obj.__dict__" 
or it can be significantly more complicated if obj has slots and super-
classes and properties. But don't worry about the complications, just 
think of "look up an attribute" as a single operation for now.

What if you don't know the name of the attribute when you are writing 
your code, but only at runtime? You want something like this:

s = "na" + "me" # We don't know this until runtime.
obj.s

but that doesn't work, because Python looks up an attribute called s.

That's where getattr(), setattr() and delattr() come into play: you can 
give the name of the attribute as a string at runtime, not hard coded in 
your source code: getattr(obj, s) evaluates s as the string "name", then 
looks up the attribute called "name" just as if you had written obj.name.

Now, what about __getattr__ __setattr__ and __delattr__? They too take 
the name of the attribute as a string, but that's about the only 
similarity with the non-underscore versions. They exist for a completely 
different reason.

The underscore versions are for customizing the lookup process, not for 
dynamically looking up names. If your class needs to do something non-
standard when you write obj.name, you might need to write methods 
__getattr__ etc.

Regardless of whether your attribute lookup was from obj.name or from 
getattr(obj, "name"), when Python goes to do the actual lookup, it will 
call on the double-underscore versions if needed:

if the __getattr__ method exists, it is ONLY called if the lookup fails;

if the __getattribute__ method exists, it is called for EVERY lookup;

if the __setattr__ method exists, it is called when you try to assign to 
an attribute;

if the __delattr__ method exists, it is called when you try to delete an 
attribute.


In a nutshell: getattr() etc. are for looking up attributes dynamically 
when you don't know the name of the attribute until runtime. __getattr__ 
etc. are for looking up attributes when you need to compute the value on 
the fly. (But an easier, less troublesome way of doing that is with 
properties.)



-- 
Steven.



More information about the Python-list mailing list