“私人" Python中的属性属性 [英] "Private" attribute properties in Python

查看:93
本文介绍了“私人" Python中的属性属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Python的新手,所以我希望我没有错过任何东西,但是这里...

I'm relatively new to Python so I hope I haven't missed something, but here goes...

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

I'm trying to write a Python module, and I'd like to create a class with a "private" attribute that can (or maybe 'should') only be modified through one or more functions within the module. This is in an effort to make the module more robust, since setting of this attribute outside of these functions could lead to unwanted behaviour. For example, I might have:

  1. 为散点图Data
  2. 存储x和y值的类
  3. 从文件读取x和y值并将其存储在类read()
  4. 中的函数
  5. 用于绘制它们的函数,plot()
  1. A class that stores x and y values for a scatter plot, Data
  2. A function to read x and y values from a file and store them in the class, read()
  3. A function to plot them, plot()

在这种情况下,我希望用户无法执行以下操作:

In this case, I would prefer if the user wasn't able to do something like this:

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

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

I realise that adding a single leading underscore to the name indicates to the user that the attribute should not be changed, i.e. rename to _x and add a property decorator so that the user can access the value without feeling guilty. However, what if I wanted to add a setter property as well:

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,但是他们仍然可以使用以下属性进行设置:

I'm now in the same position as I was before - the user can no longer directly access the attribute _x, but they can still set it using:

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

理想情况下,我将属性函数定义重命名为_x(),但这引起了对self._x实际含义的混淆(取决于声明它们的顺序,这似乎导致setter被调用递归,或者忽略该设置方法,而使用该属性.)

Ideally I'd rename the property function definitions to _x(), but this leads to confusion about what self._x actually means (depending on the order in which they are declared, this seems to result in either the setter being called recursively or the setter being ignored in favour of the attribute).

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

A couple of solutions I can think of:

  1. 在属性__x上添加双引号下划线,以使名称变得混乱,并且不会与setter函数混淆.据我了解,这应该保留给类不希望与可能的子类共享的属性,因此我不确定这是否是合法用途.
  2. 重命名属性,例如_x_stored.虽然这可以完全解决问题,但使代码更难阅读,并引入了命名约定问题-我应该重命名哪些属性?只是相关的?只是那些有属性的?只是这个班上的那些人?
  1. Add a double leading underscore to the attribute, __x, so that the name becomes mangled and does not get confused with the setter function. As I understand it, this should be reserved for attributes that a class does not wish to share with possible subclasses, so I'm not sure if this is a legitimate use.
  2. Rename the attribute, e.g. _x_stored. While this solves the problem completely, it makes the code harder to read and introduces naming convention issues - which attributes do I rename? just the ones that are relevant? just the ones that have properties? just the ones within this class?

以上两种解决方案均适用吗?如果没有,是否有更好的方法来解决此问题?

Are either of the above solutions applicable? And if not, is there a better way to solve this problem?

修改

感谢您到目前为止的回答.评论中提出了几点:

Thanks for the responses so far. A few points thrown up by the comments:

  1. 我想保留setter属性提供给我的额外逻辑-上例中的# Do something with value部分-因此,通过直接访问self._x在内部设置属性并不能解决问题.
  2. 删除setter属性并创建一个单独的函数_set_x()确实可以解决问题,但是并不是一个很整洁的解决方案,因为它允许以两种不同的方式设置_x:通过调用该函数或通过直接访问self._x.然后,我必须跟踪哪些属性应该由它们自己的(非属性)setter函数设置,以及哪些属性应通过直接访问进行修改.我可能宁愿使用我上面建议的一种解决方案,因为即使它们使类中的命名约定混乱,它们在类外的使用也至少是一致的,即它们都使用了属性的语法糖. .如果无法以更整洁的方式进行此操作,那么我想我只需要选择造成干扰最少的方法即可.
  1. I want to retain the extra logic that the setter property gives me - the # Do something with value section in the above example - so internally setting the attribute through direct access of self._x doesn't solve the problem.
  2. Removing the setter property and creating a separate function _set_x() does solve the problem, but is not a very neat solution since it allows setting of _x in two different ways - either by calling that function or through direct access of self._x. I'd then have to keep track of which attributes should be set by their own (non-property) setter function and which should be modified through direct access. I'd probably rather use one of the solutions I suggested above, because even though they make a mess of the naming conventions within the class they are at least consistent in their use outside of the class, i.e. they all use the syntactical sugar of properties. If there's no way of doing this in a neater way then I guess I just have to choose the one that causes the least disruption.

推荐答案

如果要阻止用户更改属性,但又希望清楚他们可以读取属性,我会使用@property而不提供设置器,类似于您先前描述的内容:

If you want to discourage users from changing a property, but want it to be clear that they can read it, I'd use @property without providing a setter, similar to what you described earlier:

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.

I know you mention "What if I wanted to add a setter to the property?", but I guess I would counter that with: Why add the setter if you don't want your clients to be able to set the property? Internally, you can access self._x directly.

对于直接访问_x_y的客户端,任何带有'_'前缀的变量在Python中都应理解为私有",因此您应该信任客户端来遵守.如果他们不听话,最后搞砸了,那是他们自己的错.这种思维方式与许多其他语言(C ++,Java等)相反,在这些语言中,保持数据私有非常重要,但是Python在这方面的文化有所不同.

As for a client directly accessing _x or _y, any variable with an '_' prefix is understood to be "private" in Python, so you should trust your clients to obey that. If they don't obey that, and end up screwing things up, that's their own fault. This kind of mindset is counter to a many other languages (C++, Java, etc.) where keeping data private is considered very important, but Python's culture is just different in this regard.

修改

另一个要点,由于在这种情况下,您的私有属性是列表,它们是可变的(不同于字符串或整数,它们是不可变的),客户端可能最终会意外地更改它们:

One other note, since your private properties in this particular case are lists, which are mutable (unlike strings or ints, which are immutable), a client could end up changing them somewhat accidentally:

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

如果要避免这种情况,则需要您的属性返回列表的副本:

If you want to avoid this, you'd need your property to return a copy of the list:

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

这篇关于“私人" Python中的属性属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆