Python中的“私有”属性属性

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

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

  • 存储散点图Data x和y值的类
  • 从文件中读取x和y值并将它们存储在类中的函数, read()
  • 一个函数来绘制它们, plot()
  • 在这种情况下,我宁愿如果用户不能做到这样的事情:

    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]
    

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

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

  • 向属性__x添加一个双__x下划线,这样名称就会__x并且不会与setter函数混淆。 据我了解,这应该保留给一个类不希望与可能的子类共享的属性,所以我不确定这是否合法使用。
  • 重命名该属性,例如_x_stored 。 虽然这完全解决了问题,但它使代码更难阅读并引入了命名约定问题 - 哪些属性需要重命名? 只是那些相关的? 只是那些有属性的? 只是这个班里的人?
  • 上述任一解决方案是否适用? 如果没有,是否有更好的方法来解决这个问题?

    编辑

    感谢迄今的回应。 评论提出了几点意见:

  • 我想保留setter属性赋予我的额外逻辑 - 在上面的示例中执行self._x # Do something with value部分 - 因此通过直接访问self._x来内部设置属性并不能解决问题。
  • 卸下setter属性,并创建一个单独的函数_set_x()不解决问题,而不是一个非常整洁的解决方案,因为它允许设置_x两种不同的方式-通过调用该函数或通过直接访问self._x 。 然后,我必须跟踪哪些属性应该由他们自己的(非属性)setter函数设置,哪些属性应该通过直接访问进行修改。 我可能更愿意使用上面我提到的解决方案之一,因为即使他们在类中弄乱了命名约定,他们至少在类之外的使用中一致,即它们都使用属性的语法糖。 如果没有办法以一种整洁的方式来做到这一点,那么我想我只能选择一个造成最小干扰的方法。

  • 如果您想阻止用户更改属性,但希望清楚他们可以读取它,我会在不提供setter的情况下使用@property ,与您之前描述的类似:

    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)
    
    链接地址: http://www.djcxy.com/p/20199.html

    上一篇: "Private" attribute properties in Python

    下一篇: Why is the DataGridRow IsSelected binding not working on DataGrid