tags:

views:

2735

answers:

3

This is what I'm trying to do in Python:

class BaseClass:
def __init__(self):
 print 'The base class constructor ran!'
 self.__test = 42

class ChildClass(BaseClass):

def __init__(self):
 print 'The child class constructor ran!'
 BaseClass.__init__(self)

def doSomething(self):
 print 'Test is: ', self.__test


test = ChildClass()
test.doSomething()

Which results in:

AttributeError: ChildClass instance has no attribute '_ChildClass__test'

What gives? Why doesn't this work as I expect?

+6  A: 

From python documentation:

Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them. The transformation inserts the class name in front of the name, with leading underscores removed, and a single underscore inserted in front of the class name. For example, the identifier __spam occurring in a class named Ham will be transformed to _Ham__spam. This transformation is independent of the syntactical context in which the identifier is used. If the transformed name is extremely long (longer than 255 characters), implementation defined truncation may happen. If the class name consists only of underscores, no transformation is done.

So your attribute is not named __test but _BaseClass__test.

However you should not depend on that, use self._test instead and most python developers will know that the attribute is an internal part of the class, not the public interface.

wuub
Ah... so is there a "right" or "pythonic" way then to access those private members if I need to extend a class that's using that syntax?
Keith Palmer
@Keith: It's a more OOP question than python question. By accessing a private member of a superclass, you are breaking encapsulation and creating a very strong dependency between classes. Superclass is no longer allowed to change its internal workings even if the public interface stays the same. In short: don't do that :)
wuub
Unfortunately, that means I either get to re-write the python smtpd library, or copy/paste the entire smtpd library into a new file. I don't really want to do either of those, but need access to the smtpd libraries private variables...
Keith Palmer
@Keith: You can use obj._BaseClass__attr... it's not forbidden or anything, we're all adults here etc. But it's good to knowe the consequences of doing so and try to limit it to the minimum.
wuub
+1  A: 

Double underscored variables can be considered "private". They are mangled with the class name, amongst other to protect multiple baseclasses from overriding eachothers members.

Use a single underscore if you want your attribute to be considered private by other developers.

truppo
A: 

You could use Python's introspection facilities to get you the information you are looking for. A simple dir(test) will give you

['_BaseClass__test', '__doc__', '__init__', '__module__', 'doSomething']

Note the '_BaseClass__test'. That's what you're looking for.

Check this for more information.

partoa