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