Setting Class Attributes

Bengt Richter bokr at oz.net
Tue Oct 25 21:59:38 EDT 2005


On 25 Oct 2005 15:57:41 -0700, "the.theorist" <the.theorist at gmail.com> wrote:

>
>Bruno Desthuilliers wrote:
>> the.theorist a =E9crit :
>> > I have a small, simple class which contains a dictionary (and some
>> > other stuff, not shown). I then have a container class (Big) that holds
>> > some instances of the simple class. When I try to edit the elements of
>> > the dictionary, all instances obtain those changes; I want each
>> > instance to hold separate entries.
>> >
>> > #----------Begin module test.py
>> > class ex:
>>
>> class ex(object): # oldstyle classes are deprecated
>>
>> >     def __init__(self, val=3D{}):
>> >         self.value =3D val
>>
>> You didn't search very long. This is one of the most (in)famous Python
>> gotchas: default args are evaluated *only once*, when the function
>> definition is evaluated (at load time). This is also a dirty trick to
>> have a 'static' (as in C) like variable.
>>
>> The solution is quite simple:
>> class ex(object):
>>    def __init__(self, val=3DNone):
>>      if val is None: val =3D {}
>>      self.value =3D val
>>
>> (snip)
>
>Hey, that was extremely helpful. I suspect that the default args
>evaluation is optimized for speed. So it makes sense to use the None
>assignment, and a test condition later.
That sounds like you missed the important point: The reason for using None
instead of {} as a default argument is that default arguments are only
evaluated when the function is defined, not when it's called, so if the
default value is {}, that very _same_ dict will be used as default for
the next call to __init__, so you will have every instance of ex looking
at the same val and binding it to its self.value, and then if one instance
modifies it (which it can, since a dict is mutable), the other instances
will see the modification in their self.value dicts. The None default
prevents re-use of a dict that wasn't actually passed in as an argument
replacing the default in the call. The call-time test for None discovers
that a fresh dict is needed, and self.value = {} creates that fresh dict
when __init__ executes, so the new instance gets its own separate self.value dict.

Nothing to do with optimization. In fact, re-using the shared default dict
would be faster, though of course generally wrong.
>
>Worked like a charm, Thanks!
>
Just wanted to make sure you realize why it made a difference, in case ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list