Python中的“public”或“private”属性?最好的方法是什么?

2024-04-26 14:57:42 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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”和一个属性来访问它。有很多代码可以声明一个简单的私有属性,我认为这样声明所有属性并不尊重“KISS”哲学。

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

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

最好的方法是什么?


Tags: self声明示例return属性foovaluedef
3条回答

很简单,OOP原则是错误的。为什么这是一个漫长的讨论,导致了火焰战争,可能是这个网站的话题。:-)

在Python中没有私有属性,您不能保护它们,这从来不是一个真正的问题。所以别这么简单!:)

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

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

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

一些例子:

>>> 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.

通常,Python代码努力遵守Uniform Access Principle。具体而言,公认的方法是:

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

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

foo.x += 1

即使代码可能真的在做:

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

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

还要注意,以一个下划线开头的实例变量通常是私有的。也就是说,下划线向其他开发人员发出信号,表示您认为该值是私有的,他们不应该直接处理它;但是,语言中的任何东西都不能阻止他们直接处理它。

如果使用双前导下划线(例如__x),Python会对名称做一些模糊处理。但是,该变量仍然可以通过其模糊名称从类外部访问。这不是真正的隐私。只是有点。。。更不透明。还有一些反对使用双下划线的有效论据;首先,它会使调试变得更加困难。

相关问题 更多 >