【问题标题】:Exposing members or make them private in Python?在 Python 中公开成员或将其设为私有?
【发布时间】:2011-02-13 20:29:48
【问题描述】:

是否有关于在 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 方法吗?

【问题讨论】:

  • 1) 取决于 2) 孩子 -> 孩子。

标签: python oop visibility


【解决方案1】:

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

在任何情况下,成员仍然可以公开访问;这只是一个约定。

【讨论】:

    【解决方案2】:

    我认为,除非您有明确的理由不这样做,否则让成员暴露在 Python 中更符合 Python 风格,因为 Python 代码通常不打算限制用户超出必要的范围。这就是为什么,例如,没有真正私人成员这样的东西。

    【讨论】:

      【解决方案3】:

      考虑将某些内容作为文档公开还是私有。它显示了您对成员范围的意图,并作为对其他开发人员的警告,它可能在未来发生变化。

      【讨论】:

        【解决方案4】:
        • 答案当然是“视情况而定”。如果我猜的话,我会使用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 += ba = a + b 有两个不同之处:前者对原始列表进行变异,后者创建一个新列表并将其重新绑定到原始名称,后者b 必须是一个列表,而前者@ 987654335@ 可以是任意可迭代的。我找到了extend 清洁工。

        • 我总是继承object 而不是什么都没有,即class Node(object):,所以我使用的是新式类。新式类的工作方式更加原生,并且有一些旧式类没有的功能。

        【讨论】:

          【解决方案5】:

          “视情况而定。”

          说真的。如果 Node 在添加孩子时需要做某事,您会希望第一个抓住变化并做需要做的事情。如果它只是一个您不需要担心更改的列表,请选择后者。

          【讨论】:

            【解决方案6】:

            正如你所说,这取决于。一般来说,我更喜欢有一种与类交互的方法,以分离编程逻辑和它的实现。按照您发布的示例,我会写:

            class Node:
            
              def __init__(self):
                  self.childs = []
            
              def add_childs(self, *args):
                  self.childs += args
            

            因为如果一个子类可以访问childs,它就可以不用任何奇怪的变量名。 通常我只使用带有属性的私有成员来缓存计算值。

            【讨论】:

              【解决方案7】:

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

              双下划线前缀调用名称修改。在您看来,该属性可能是私有的,但您可以像这样访问它。

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

              【讨论】:

                猜你喜欢
                • 2011-11-02
                • 2015-05-03
                • 2013-06-08
                • 2014-09-22
                • 2011-09-10
                • 1970-01-01
                • 2017-05-30
                • 2010-10-07
                相关资源
                最近更新 更多