Initializing Member Variables

Francis Avila francisgavila at yahoo.com
Mon Mar 8 20:37:14 CET 2004


In <c2i9vi$mip$1 at news01.intel.com> Scott Brady Drummonds wrote:
> Hi, everyone,
> 
> 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())

..

> 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.  

In Python, class is an object. (This is by no means unusual among OO 
languages.)  So __dict, __init__, basically anything defined at the 
first level of indentation after the 'class :' line is a member of the 
class object pointed to by the class's name.

untested code:

>>> class A:
.. 	aName={}
..
>>> one = A()
>>> two = A()
>>> one.aName is two.aName
True
>>> {} is {}
False
>>>

Of course, this is more annoying to test with your class because you 
make dict private.  Unless you have a very good reason, don't do that (
you can get around it anyway).  One underscore is enough.

> 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 need to be introduced to Python's name-binding concepts, and purge 
yourself of this "variable" idea. :)

This may help:
http://starship.python.net/crew/mwh/hacks/objectthink.html

But I'll summarize.

In Python, you have not variables, but names.  Names point to objects (
that's all names do).  Objects can possess (as in "hold", not "be called 
by").  But objects themselves have no intrinsic name.

So:
>>> a = [] # a name pointing to a list object
>>> b = a 

b points not to a (you can't point at names) but to the object pointed 
to by a.  The name 'b' is "bound" to the list object.

The = is the "binding" keyword.  Note, *keyword*, not operator. (Ok, 
it's not listed as a keyword, but it's not listed as an operator, either.) 
You might have noticed you can't overload it. That's why.

Continuing on...

>>> b.append(1) # we modify the object b points to.
>>> a # but a still points to the same object, now modified.
[1]
>>> a is b
True
>>> vars() # the current namespace, i.e. name:object pairs.
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__
', 'b': [1], '__doc__': None, 'a': [1]}
>>> 

Some subtlety arises because in Python, some objects are mutable, others 
immutable.  If its immutable, then whenever you might think you're 
pointing to the same object, you're probably pointing to a newly-created 
object (e.g., string concatenation or slicing makes new strings, 
addition makes new integers, etc.).  Not always though, because if you 
"intern" the object (using intern()), then Python checks if one already 
exists (even if no name is bound to it) before creating a new one.  
Interned objects are immortal for this reason.

> 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?

No.  __init__ *alone* is responsible for initalizing them and __new__ is 
responsible for creating them (which you'll rarely need).  Python 
doesn't do any copying or other such magic when making an object from a 
class, so objects defined in a class possess a name pointing to only one 
object.  Instances of that class get their own new name, but that name 
points to the same object, not a copy of it (unless either __new__ or __
init__ rebound the name, of course...).

So if you want a new member (i.e. a unique object) for every instance, 
create it in __init__:

class Keys:
	def __init__(self, key):
		self._dict = {}			# Do this.
		self._dict[key] = key
		print('keys are now: %s' % self._dict.keys())

-- 
Francis Avila



More information about the Python-list mailing list