Python does not have the private member variables that many programming languages do. I observe three strategies in use to simulate them, none effective. [Edit:] I don't advocate this; it's not Pythonic. But it's useful to be able to recognize in code one is reading or contributing to.
One convention is that a leading single underscore can be use as an
"advisory" or "soft" privacy notation. So a method named method()
is
meant to be public, while _method()
is supposed to be treated as
private. The leading underscore helps coders to remember not to use it,
although there is no way to keep them from using it if they want to.
A second strategy is the use of such things as private class variables. These exist mainly not for the sake of privacy but to avoid collisions between variables with the same name that originate in different classes. They are marked as private by the use of two distinguishing characteristics:
- they are named with a leading "dunder" (double underscore, i.e.,
__
). - "mangling" (alteration) of their names: in order to access them outside of their own class, you prefix the dunder with an additional single underscore and the name of the class itself.
TheClass
containing a method
called __method()
, the method can be called on some object thing
not
as plain
> thing.\_\_method()
but as
> thing.\_TheClass\_\_method()
I have posted a little piece of code called degrees_of_privacy.py
to
my BitBucket repository to illustrate the syntax and effects of this
and the "advisory" usages. But even these supposedly private variables
are fully accessible outside of their own classes, as long as they are
correctly named, unlike true private member variables in C++ and other
languages.
A third strategy I have observed is that some coders use a single underscore before the public form of a variable's name and no underscore before the nominally private form of the same variable. In 2009, John Reid posted code for a red black tree with a class definition beginning this way:
> class rbnode(object): > >
The point is that (based on a reading of Reid's code)
def __init__(self, key):
self._key = key
key
is
apparently meant to be a private variable and _key
a public one.
Similarly, Bruno Preiss, in his [interesting 2003 on-line book of data
structures and algorithms in Python][] uses syntax of the form:
> class Element(object): > >
Again,
def __init__(self, list, datum, next):
self._list = list
self._datum = datumself._next = next
list
seems meant to be private and _list
public. There is a
similar prescription in the Wikipedia article on mutator methods
(accessed 20111017):
> class Student(): > >
I wonder where this syntax comes from, since the official Python documentation and reference books I have consulted do not mention it, and after all these variables cannot be private in the true sense. Reid and Preiss enforce their private variables as static (unmodifiable or read-only) by use of the
def __init__(self, name):
self._name = name
property()
function with the fget
function:
> key = property(fget=lambda self: self.\_key, doc="The node's key")
(from Reid). Here _key
can be changed outside of the class itself, but
key
cannot in the absence of fset
or fdel
as an argument of
property()
. That is just the opposite of the "advisory" leading
underscore described near the beginning of this posting.
I can't help thinking that I am looking at indirect influence from C++. Reid and Preiss are both modeling nodes — Reid for a binary tree and Preiss for a linked list, both structures for which a language with pointers would be natural. Reid (following the pseudocode in the algorithms book by Cormen et al.) has some objects of the form
> z.p.p.right
meaning the right
attribute of an object p
, which is itself the
attribute of a different object p
, itself the attribute of still
another object z
. I can't think of a simpler way than this to model
the nodes of graphs and trees in Python, though it does call to mind a
similar pointer construction
> ((z-\>p)-\>p)-\>right
in C++. Perhaps this is an earlier version (or a recollection) of forms like
> \_TheClass\_\_method()
cited above.
[interesting 2003 on-line book of data structures and algorithms in Python]: http://www.brpreiss.com/books/opus7/programs/pgm04_11.txt