Always decide whether a class's
methods and instance variables (collectively: "attributes") should
be public or non-public. If in doubt, choose non-public; it's
easier to make it public later than to make a public attribute
non-public.
Public attributes are those that you
expect unrelated clients of your class to use, with your commitment
to avoid backward incompatible changes. Non-public attributes are
those that are not intended to be used by third parties; you make
no guarantees that non-public attributes won't change or even be
removed.
We don't use the term "private" here,
since no attribute is really private in Python (without a generally
unnecessary amount of work).
Another category of attributes are
those that are part of the "subclass API" (often called "protected"
in other languages). Some classes are designed to be inherited
from, either to extend or modify aspects of the class's behavior.
When designing such a class, take care to make explicit decisions
about which attributes are public, which are part of the subclass
API, and which are truly only to be used by your base class.
With this in mind, here are the
Pythonic guidelines:
Public attributes should
have no leading underscores.
If your public attribute
name collides with a reserved keyword, append a single trailing
underscore to your attribute name. This is preferable to an
abbreviation or corrupted spelling. (However, notwithstanding this
rule, 'cls' is the preferred spelling for any variable or argument
which is known to be a class, especially the first argument to a
class method.)
Note 1: See the argument name
recommendation above for class methods.
For simple public data
attributes, it is best to expose just the attribute name, without
complicated accessor/mutator methods. Keep in mind that Python
provides an easy path to future enhancement, should you find that a
simple data attribute needs to grow functional behavior. In that
case, use properties to hide functional implementation behind
simple data attribute access syntax.
Note 1: Properties only work on
new-style classes.
Note 2: Try to keep the functional
behavior side-effect free, although side-effects such as caching
are generally fine.
Note 3: Avoid using properties for
computationally expensive operations; the attribute notation makes
the caller believe that access is (relatively) cheap.
If your class is
intended to be subclassed, and you have attributes that you do not
want subclasses to use, consider naming them with double leading
underscores and no trailing underscores. This invokes Python's name
mangling algorithm, where the name of the class is mangled into the
attribute name. This helps avoid attribute name collisions should
subclasses inadvertently contain attributes with the same name.
Note 1: Note that only the simple
class name is used in the mangled name, so if a subclass chooses
both the same class name and attribute name, you can still get name
collisions.
Note 2: Name mangling can make certain
uses, such as debugging and __getattr__(), less convenient. However the
name mangling algorithm is well documented and easy to perform
manually.
Note 3: Not everyone likes name
mangling. Try to balance the need to avoid accidental name clashes
with potential use by advanced callers.