Initializing Member Variables

Peter Otten __peter__ at web.de
Mon Mar 8 13:37:05 EST 2004


Scott Brady Drummonds wrote:

> I'm a Python novice and just diagnosed a problem that is confusing me.  I
> wrote a class that looks like this:
> 
> class Keys:
>   __dict = {}
> 
>   def __init__(self, key):
>     self.__dict[key] = key
>     print('keys are now: %s' % self.__dict.keys())
> 
> 
> When I test this class from my Python interpreter (interactive), I see the
> following strange behavior:
> 
>>>> import keys
>>>> k1 = keys.Keys('1')
> keys are now: ['1']
>>>> k2 = keys.Keys('2')
> keys are now: ['2', '1']
>>>> k3 = keys.Keys('4')
> keys are now: ['4', '2', '1']
>>>>
> 
> 
> Maybe this isn't strange for a Python developer, but it sure is for me.  I
> thought that the "__dict = {}" line after the class declaration was
> supposed
> to initialize that member variable for each object.  Obviously, that's not
> happening.  Instead, that variable is retaining its value from one object
> to
> the next, like a static member variable.  For what it's worth, it seems
> that this static variable behavior is not observed when using scalar
> variables. Just with dictionaries.

You've pretty much answered it yourself, except for the last sentence. The
difference is not scalars versus vectors but rebinding versus mutating.

a = {} # rebind a
a = b  # rebind a

is fundamentally different from

a[key] = value # change a's value

As strings and integers are immutable you are always using only the first
pattern - it doesn't matter if you reuse the same object in several places,
because its value can never change.

> Where have I gone wrong?  What is the purpose of that "initialization" in
> the Keys class?  What is the correct was to initialize a class's member
> variable and guarantee that it is properly initialized for all objects?

self.__dict used in the __init__() method is misleading in your case,
because if the attribute is not found in the instance, lookup proceeds to
the class. This may have funny effects:

>>> class A:
...     b = 1
...
>>> a = A()
>>> a.b
1
>>> a.b = 2 # create an instance attribute
>>> a.b     # the class attribute is now shadowed...
2
>>> A.b     # ...but still there
1
>>> del a.b # delete the instance attribute
>>> a.b     # the class atttribute is visible again
1

Putting it all together: create the dictionary in the __init__() method
instead of the class body (and while we're at it - do you really need that
extra privacy provided by the double underscore?):

>>> class Keys:
...     def __init__(self, key):
...             self._dict = {}
...             self._dict[key] = key
...
>>> k = Keys("first")
>>> k2 = Keys("second")
>>> k._dict
{'first': 'first'}
>>> k2._dict
{'second': 'second'}
>>>

Peter



More information about the Python-list mailing list