公开成员或在Python中将它们设为私有?

时间:2010-04-29 14:33:38

标签: python oop visibility

是否存在关于在Python类中公开成员的一般约定?我知道这是“依赖”的情况,但也许有一个经验法则。

私人会员:

class Node:

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

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

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

公共成员:

class Node2:

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

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

如果没有充分的理由让children变为私有,您会继续使用方法add_children吗?

7 个答案:

答案 0 :(得分:5)

“private”的前缀是单个下划线。 __用于破坏名称并避免一些问题,例如何时使用多重继承。 我个人从未使用它。

无论如何,成员仍然可以公开访问;这只是一个惯例。

答案 1 :(得分:3)

我认为除非你有特别的理由不让成员公开,否则更多Pythonic,因为Python代码通常不打算限制用户超出必要的范围。这就是为什么,例如,没有真正的私人成员。

答案 2 :(得分:2)

考虑选择公开或私人作为文档。它显示了您对成员范围的意图,并向其他开发人员发出警告,告知其未来可能会发生变化。

答案 3 :(得分:2)

  • 答案当然是“它取决于”。如果我猜,我会使用add_children方法。类的要点通常是从你存储的状态的表示中抽象出你正在做的事情。 my_node.add_children(a, b)是我将读作“将孩子a和b添加到我的模式”的操作。 my_node.children.extend([a, b])使用户将children视为列表,并在实例内部进行调整以使其变异。这有时候,但不常见,你想要的。如果您最终需要添加子项以执行其他操作,也很难不进行API更改。

  • __foo属性不是私有的。 Python名称 - 以系统化,易于重现的方式破坏它们。 Python不支持真正的私有属性。使用__foo不会增加隐私,但它会让您的课程更难以测试,继承和使用。

    当我有一个我不希望作为公共API一部分的属性时,我在它前面加上一个下划线,例如: _foo。该惯例被广泛使用。

  • 我从不在列表中使用+=;我改用extend方法。我不喜欢+=,因为大多数人都使用extend,因为它的操作有点令人困惑。 a += b在两个方面与a = a + b不同:前者改变原始列表,后者创建新列表并将其重新绑定到原始名称,后者b必须是列表和前b中的列表可以是任意可迭代的。我发现extend更清洁了。

  • 我总是继承object而不是class Node(object):,所以我正在使用新式类。新式课程更加本土化,并且有一些旧式课程没有的功能。

答案 4 :(得分:1)

“这取决于。”

严重。如果Node需要在添加子项时执行某些操作,那么您需要先了解更改并执行需要完成的操作。如果它只是一个您不需要担心变化的列表,那么请使用后者。

答案 5 :(得分:0)

正如你所说,这取决于。通常我更喜欢有一种与类交互的方法,以便在编程逻辑和它的实现之间进行分离。按照您发布的示例,我将写下:

class Node:

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

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

因为如果一个子类可以访问childs,那么它可以没有任何奇怪的varname。 通常我只使用属性的私有成员来创建计算值的缓存。

答案 6 :(得分:0)

约定是使用单个下划线作为前缀,但它纯粹是建议性的,并且仍然可以像访问任何其他属性一样访问该属性。在编写单元测试时有时很方便

双下划线前缀调用名称重整。您可能会觉得该属性是私有的,但您可以像这样访问它。

>>> node=Node()
>>> node._Node__children
[]