def __init__ question in a class definition rephrased

Steven Bethard steven.bethard at gmail.com
Mon Feb 7 18:39:56 EST 2005


Jeffrey Borkent wrote:
> what is the significance ( if any ) of the __ in these self.xxxxxx
> assignments.

Variables with preceding __ are a vague attempt to avoid some types of 
name collisions in inheritance hierarchies.  Any name that starts with a 
__ will be mangled by prefixing it with _<class-name>:

py> class C(object):
...     def __init__(self, x):
...         self.__type = type(x)
...         self.x = x
...
py> C(1).__dict__
{'_C__type': <type 'int'>, 'x': 1}
py> class D(C):
...     def __init__(self, x):
...         super(D, self).__init__(x)
...         self.__type = D
...
py> D(1).__dict__
{'_C__type': <type 'int'>, 'x': 1, '_D__type': <class '__main__.D'>}

Note that the D object has two different __type attributes -- one 
mangled for type C and one mangled for type D.

While the intent of __ variables is to allow you to not worry about the 
names given to "private" attributes of a class when you inherit from 
that class, it doesn't actually achieve this in all cases -- you'll 
still have problems if you inherit from two classes with the same names 
that use the same __ attribute:

---------- a.py ----------
class A(object):
     pass

---------- b.py ----------
import a

class X(a.A):
     def __init__(self):
         self.__x = 'b.X.__x'
         super(X, self).__init__()

---------- c.py ----------
import a

class X(a.A):
     def __init__(self):
         self.__x = 'c.X.__x'
         super(X, self).__init__()

---------- d.py ----------
import b, c

class D(b.X, c.X):
     pass

--------------------------

py> import d
py> d.D().__dict__
{'_X__x': 'c.X.__x', '_A__x': 'A'}

Note that the D object has two __x attributes, not three, like it 
should.  Code in b.py which depends on the __x attribute is now broken 
because __x should should have the value 'b.X.__x' but instead it has 
the value from the c module, 'c.X.__x'.


The solution to this is to have names mangled with their module name as 
well, but that's backwards incompatible, so Python's not likely to 
change that way.


My general feeling here is that "we're all consenting adults", and that 
__ is probably not helpful in most cases.  If you simply don't want the 
attribute shown by, say, pydoc, prefixing a single underscore should be 
sufficient and doesn't invoke the name-mangling.

STeVe



More information about the Python-list mailing list