Python中的“私有”属性属性
我对Python比较陌生,所以我希望我没有错过任何东西,但是在这里...
我正在尝试编写一个Python模块,并且我想创建一个具有“private”属性的类,该属性可以(或者可能'应该')只能通过模块中的一个或多个函数进行修改。 这是为了使模块更健壮,因为在这些功能之外设置此属性可能会导致不需要的行为。 例如,我可能会:
Data
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
。 虽然这完全解决了问题,但它使代码更难阅读并引入了命名约定问题 - 哪些属性需要重命名? 只是那些相关的? 只是那些有属性的? 只是这个班里的人? 上述任一解决方案是否适用? 如果没有,是否有更好的方法来解决这个问题?
编辑
感谢迄今的回应。 评论提出了几点意见:
self._x
# Do something with value
部分 - 因此通过直接访问self._x
来内部设置属性并不能解决问题。 _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