“private” methods in Python

Python supports semi-private methods through a name mangling trick. The interpreter transforms method names starting with two underscores by prepending it with the class name and some additional underscores, so it becomes impossible to call the method by its original name. Here’s an example:

>>> class T(object):
... def __m(self): pass
...
>>> t = T()
>>> dir(t)
['_T__m', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> t.__m()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: 'T' object has no attribute '__m'

It is still possible to call the method using its mangled name.

Fortunately, one can still use the original name from within other methods of the same class:

>>> class T(object):
... def __m(self): print "m"
... def public(self): self.__m()
...
>>> t = T()
>>> t.public()
m

It works because bytecode generated for this method uses the mangled name:

>>> import dis
>>> dis.dis(t.public)
 3 0 LOAD_FAST 0 (self)
 3 LOAD_ATTR 0 (_T__m)
 6 CALL_FUNCTION 0
 9 POP_TOP
 10 LOAD_CONST 0 (None)
 13 RETURN_VALUE

Post prompted by a colleague’s question.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s