Python中的“私有”属性属性

时间:2014-05-02 15:57:50

标签: python properties attributes private

我对Python比较陌生,所以我希望我没有错过任何东西,但这里有......

我正在尝试编写一个Python模块,并且我想创建一个带有"私有"可以(或者可能'应该')仅通过模块中的一个或多个功能修改的属性。这是为了使模块更加健壮,因为在这些函数之外设置此属性可能会导致不必要的行为。例如,我可能有:

  1. 存储散点图的x和y值的类Data
  2. 从文件中读取x和y值并将其存储在类read()
  3. 中的函数
  4. 绘制它们的函数,plot()
  5. 在这种情况下,如果用户无法做到这样的话,我更愿意这样做:

    data = Data()
    read("file.csv", data)
    data.x = [0, 3, 2, 6, 1]
    plot(data)
    

    我意识到在名称中添加一个前导下划线表示用户不应更改属性,即重命名为_x并添加属性装饰器,以便用户可以访问该值而不会感到内疚。但是,如果我想添加一个setter属性该怎么办:

    class Data(object):
        _x = []
        _y = []
        @property
        def x(self):
            return self._x
        @x.setter
        def x(self, value):
            # Do something with value
            self._x = value
    

    我现在处于和以前一样的位置 - 用户无法再直接访问属性_x,但他们仍然可以使用以下内容进行设置:

    data.x = [0, 3, 2, 6, 1]
    

    理想情况下,我将属性函数定义重命名为_x(),但这会导致对self._x实际含义的混淆(取决于它们的声明顺序,这似乎是结果在递归调用setter或者忽略setter以支持属性)。

    我能想到的几个解决方案:

    1. 在属性__x中添加一个双前导下划线,以便名称变得严重,并且不会与setter函数混淆。据我了解,这应该保留给类不希望与可能的子类共享的属性,因此我不确定这是否是合法使用。
    2. 重命名该属性,例如_x_stored。虽然这完全解决了这个问题,但它使代码更难阅读并引入了命名约定问题 - 我会重命名哪些属性?只是那些相关的?只是有属性的?只是这堂课的那些?
    3. 以上哪种解决方案都适用?如果没有,是否有更好的方法来解决这个问题?

      修改

      感谢目前为止的回复。评论提出了几点:

      1. 我想保留setter属性为我提供的额外逻辑 - 上例中的# Do something with value部分 - 因此通过直接访问self._x来内部设置属性并不能解决问题问题。
      2. 删除setter属性并创建单独的函数_set_x()确实解决了问题,但不是一个非常简洁的解决方案,因为它允许以两种不同的方式设置_x - 通过调用该函数或通过直接访问self._x。然后,我必须跟踪哪些属性应该由他们自己的(非属性)setter函数设置,哪些属性应该通过直接访问来修改。我可能更倾向于使用我上面提到的解决方案之一,因为尽管它们在类中混淆了命名约定,但它们在类之外的使用中至少是一致的,即它们都使用语法糖属性。如果没有办法以更简洁的方式做到这一点,那么我想我只需要选择一个导致破坏最少的那个。

1 个答案:

答案 0 :(得分:4)

如果您想阻止用户更改某个媒体资源,但希望它能够清楚地表明他们可以阅读该媒体资源,我会在不提供设置工具的情况下使用@property,类似于您之前描述的内容: / p>

class Data(object):
    def __init__(self):
       self._x = []
       self._y = []

    @property 
    def x(self):
        return self._x

    @property 
    def y(self):
        return self._x

我知道你提及"如果我想在房产中添加一个二传手?怎么办?",但我想我会反驳:如果你不想要你的话,为什么要添加二传手?客户能够设置属性?在内部,您可以直接访问self._x

对于直接访问_x_y的客户,任何带有' _'的变量前缀被理解为"私人"在Python中,所以你应该相信你的客户服从它。如果他们不遵守这一点,并最终搞砸了,那就是他们自己的错。这种心态与许多其他语言(C ++,Java等)相反,其中保持数据私密性被认为是非常重要的,但Python的文化在这方面是不同的。

修改

还有另一个注意事项,因为在这种特殊情况下你的私有属性是可变的列表(不同于字符串或整数,它们是不可变的),客户端最终可能会意外地改变它们:

>>> d = Data()
>>> print d.x
['1', '2']
>>> l = d.x
>>> print l
['1', '2']
>>> l.append("3")
>>> print d.x
['1', '2', '3']  # Oops!

如果你想避免这种情况,你需要你的财产返回一份清单:

@property
def x(self):
    return list(self._x)