关于oop:python中的”public”或”private”属性?最好的方法是什么?

“public” or “private” attribute in Python ? What is the best way?

在python中,我有以下示例类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Foo:
    self._attr = 0

    @property
    def attr(self):
        return self._attr

    @attr.setter
    def attr(self, value):
        self._attr = value

    @attr.deleter
    def attr(self):
        del self._attr

如您所见,我有一个简单的"private"属性"attr"和一个访问它的属性。有很多代码可以声明一个简单的私有属性,我认为这样声明所有属性并不尊重"吻"哲学。

那么,如果我不需要一个特定的getter/setter/deleter,为什么不将我的所有属性声明为公共属性呢?

我的答案是:因为封装原理(oop)说的不是这样!

最好的方法是什么?


通常,python代码力求遵循统一的访问原则。具体来说,公认的方法是:

  • 直接公开实例变量,例如,允许foo.x = 0,而不是foo.set_x(0)
  • 如果您出于任何原因需要将访问包装在方法中,请使用@property,它保留了访问语义。也就是说,foo.x = 0现在调用foo.set_x(0)

这种方法的主要优点是调用者可以这样做:

1
foo.x += 1

即使代码可能真的在做:

1
foo.set_x(foo.get_x() + 1)

第一条语句的可读性无限强。然而,使用属性,您可以添加(在开始时,或稍后)使用第二种方法获得的访问控制。

请注意,以单个下划线开头的实例变量通常是私有的。也就是说,向其他开发人员发出的下划线信号表明,您认为价值是私有的,他们不应该直接处理它;但是,语言中没有任何内容阻止他们直接处理它。

如果使用双前导下划线(例如,__x),python会稍微混淆名称。但是,变量仍然可以通过其模糊的名称从类外部访问。这不是真正的私密。只是有点…更加不透明。还有一些有效的论点反对使用双下划线;一方面,它会使调试更加困难。


"dunder"(双下划线,__前缀)防止访问属性,除非通过访问器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Foo():
    def __init__(self):
        self.__attr = 0

    @property
    def attr(self):  
        return self.__attr

    @attr.setter
    def attr(self, value):
        self.__attr = value

    @attr.deleter
    def attr(self):
        del self.__attr

一些例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> f = Foo()
>>> f.__attr                          # Not directly accessible.
Traceback (most recent call last):
  File"<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__attr'
>>> '__attr' in f.__dir__()           # Not listed by __dir__()
False
>>> f.__getattribute__('__attr')      # Not listed by __getattribute__()
Traceback (most recent call last):
  File"<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__attr'
>>> f.attr                            # Accessible by implemented getter.
0
>>> f.attr = 'Presto'                 # Can be set by implemented setter.
>>> f.attr
'Presto'
>>> f.__attr = 'Tricky?'              # Can we set it explicitly?
>>> f.attr                            # No. By doing that we have created a
'Presto'                              # new but unrelated attribute, same name.


很简单,OOP原则是错误的。为什么这是一个长期的讨论,导致火焰大战,可能是这个网站的主题以外。-)

在Python中,没有私有属性,您不能保护它们,这从来不是真正的问题。所以不要。放松!:)

接下来的问题是:您是否应该有一个前导下划线。在这里的例子中,你绝对不应该。python中的一个前导下划线是一种惯例,它表明某些东西是内部的,而不是API的一部分,并且您应该自担风险地使用它。这显然不是这里的情况,但这是一个常见且有用的惯例。


python没有公共或私有属性。所有代码都可以访问所有属性。

1
self.attr = 0 #Done

你的方法并没有使你的隐私化,只是有点模糊。


正如其他人所说,Python中的私有属性只是一种约定。在绑定、修改或删除属性时,应使用property语法进行特殊处理。python的好处在于,您可以从使用普通属性绑定开始,例如,self.attr = 0,如果在以后某个时候您决定将attr的值限制为0 <= attr <=100,则可以使attr成为一个属性,并定义一个方法来确保该条件是正确的,而不必更改任何用户代码。


湖本链接:http://///classes.html docs.python.org教程2

9.6。私有变量和一流的本地参考

"私人"是不能访问实例变量,除了从内部在Python中的对象不存在。然而,他们有一个会议,是由Python代码:A字头最有下划线的名称(例如_垃圾邮件)应处理作为一个非公开的API的一部分(无论它是一个函数,a的方法或数据成员)。它应该被视为在没有实施细节与主题的变更通知。

因为有一个有效的用例(即私有成员的类的名称,以避免冲突的姓名名称定义subclasses)有限公司的支持,有这样一个机制,所谓的名字。任何形式的垃圾邮件的_ _标识符(至少两个尾随领先的下划线,下划线,在一个指定的textually)是没有_ _ _ classname是垃圾邮件,在领先的流类名称有下划线的(S)的剥离。这是他做不到"句法位置标识符时,只要它在一类的定义。


要使属性私有化,只需执行EDOCX1[10]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Foo:
    self.__attr = 0

    @property
    def attr(self):
        return self._attr

    @attr.setter
    def attr(self, value):
        self._attr = value

    @attr.deleter
    def attr(self):
        del self._attr


属性的好处在于它们为您提供了一个非常酷的界面。有时,基于其他属性(即体重指数由体重和身高定义)来推导属性很方便。当然,界面的用户不必知道这一点。

我更喜欢使用显式的吸收器和设置器,如Java IE.Way-Neer-ER。:)


在Python中,除非需要属性之外的特殊行为,否则不需要将其隐藏在访问器方法后面。如果属性仅供内部使用,请在其前面加下划线。