views:

91

answers:

7

Is there a general convention about exposing members in Python classes? I know that this is a case of "it depends", but maybe there is a rule of thumb.

Private member:

class Node:

  def __init__(self):
    self.__children = []

  def add_children(self, *args):
    self.__children += args

node = Node()
node.add_children("one", "two")

Public member:

class Node2:

  def __init__(self):
    self.children = []

node2 = Node2()
node2.children += "one", "two"

If there is no good reason to make children private, would you stay with the method add_children?

+4  A: 

The prefix for "private" is a single underscore. __ is used to mangle the name and avoid some problems e.g. when using multiple inheritance. Personnally I've never used it.

In any case, the members will still be publicly accessible; this is just a convention.

Bastien Léonard
+3  A: 

I believe it is more Pythonic to leave members exposed unless you have specific reason not to, on the basis that Python code generally does not intend to restrict the user any more than is necessary. This is why, for example, there is no such thing as a truly private member.

danben
+1  A: 

"It depends."

Seriously. If the Node needs to do something when children are added, you'd want the first to catch the change and do what needs to be done. If it's just a list that you don't need to worry about changes, go with the latter.

AFoglia
+2  A: 

Think of the choice of making something public or private as documentation. It shows your intent for the scope of a member, and serves as a warning to other developers that it may change in the future.

Bryan Oakley
A: 

As you said, it depends. Generally i prefer have a method to interact with a class to get a separation between programming logic and it's implementation. Following the example that you posted, i will have wrote:

class Node:

  def __init__(self):
      self.childs = []

  def add_childs(self, *args):
      self.childs += args

because if a subclass would access to childs it could without any strange varname. Usually i use private members only with properties to make a cache of a computed value.

mg
A: 

The convention is to prefix with a single underscore, however it is purely advisory and it is still possible to access to the attribute just like any other. Handy sometimes when you are writing unit tests

The double underscore prefix invokes name mangling. It may appear to you that the attribute is private, but you can access it like this.

>>> node=Node()
>>> node._Node__children
[]
gnibbler
+2  A: 
  • The answer is, of course, "it depends". If I was to guess, I would use an add_children method. The point of a class is usually to abstract away what you are doing from the representation of the state you are storing. my_node.add_children(a, b) is an operation I would read as "add children a and b to my mode". my_node.children.extend([a, b]) makes the user think of children as a list and reach down inside of the instance to mutate it. This is sometimes, but less often, what you want. It also makes it hard not to have an API change if you eventually need adding children to do something additional.

  • __foo attributes are not private. Python name-mangles them in a systematic, easily-reproducable way. Python does not support real private attributes. Using __foo does not add privacy, but it does make your class harder to test, inherit, and use.

    When I have an attribute I don't want as part of my public API, I prefix it with a single underscore, e.g. _foo. This convention is widely used.

  • I never use += with lists; I use the extend method instead. I don't like += because most people use extend and because its operation is a little confusing. a += b is different from a = a + b in two ways: the former mutates the original list and the latter creates a new list and rebinds it to the original name, and in the latter b must be a list and in the latter b may be an arbitrary iterable. I find extend cleaner.

  • I always inherit object rather than nothing, i.e. class Node(object):, so that I am using new-style classes. New-style classes work in a little more native a way and have a few features old-style classes don't.

Mike Graham