我应该使用“公共”吗?属性或“公共”属性Python 中的属性?

发布于 2024-10-09 18:19:19 字数 472 浏览 9 评论 0原文

在 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

如您所见,我有一个简单的“私有”属性“_attr”和一个用于访问它的属性。有很多代码来声明一个简单的私有属性,我认为这样声明所有属性并不尊重“KISS”哲学。

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

我的回答是: 因为封装原则(OOP)另有规定!

最好的方法是什么?

In Python, I have the following example class:

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

As you can see, I have a simple "private" attribute "_attr" and a property to access it. There is a lot of codes to declare a simple private attribute and I think that it's not respecting the "KISS" philosophy to declare all attributes like that.

So, why not declare all my attributes as public attributes if I don't need a particular getter/setter/deleter?

My answer will be:
Because the principle of encapsulation (OOP) says otherwise!

What is the best way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

囚你心 2024-10-16 18:19:19

通常,Python 代码努力遵守统一访问原则。具体来说,可接受的方法是:

  • 直接公开实例变量,例如允许 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 会对名称进行一些混淆。然而,该变量仍然可以通过其模糊名称从类外部访问。这不是真正的私人。它只是有点……更不透明。反对使用双下划线也是有道理的;一方面,它会使调试变得更加困难。

Typically, Python code strives to adhere to the Uniform Access Principle. Specifically, the accepted approach is:

  • Expose your instance variables directly, allowing, for instance, foo.x = 0, not foo.set_x(0)
  • If you need to wrap the accesses inside methods, for whatever reason, use @property, which preserves the access semantics. That is, foo.x = 0 now invokes foo.set_x(0).

The main advantage to this approach is that the caller gets to do this:

foo.x += 1

even though the code might really be doing:

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

The first statement is infinitely more readable. Yet, with properties, you can add (at the beginning, or later on) the access control you get with the second approach.

Note, too, that instance variables starting with a single underscore are conventionally private. That is, the underscore signals to other developers that you consider the value to be private, and they shouldn't mess with it directly; however, nothing in the language prevents them from messing with it directly.

If you use a double leading underscore (e.g., __x), Python does a little obfuscation of the name. The variable is still accessible from outside the class, via its obfuscated name, however. It's not truly private. It's just kind of ... more opaque. And there are valid arguments against using the double underscore; for one thing, it can make debugging more difficult.

半世晨晓 2024-10-16 18:19:19

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

但是,您可以通过名称修改(_classname__attribute)来访问此类属性,Python 在后台执行此操作:

>>> f._Foo__attr
0
>>> f.__getattribute__('_Foo__attr')
0

The "dunder" (double underscore, __) prefix prevents access to attribute, except through accessors.

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

Some examples:

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

However, you can access this type of attribute through name mangling (_classname__attribute), which Python does in the background:

>>> f._Foo__attr
0
>>> f.__getattribute__('_Foo__attr')
0
一抹淡然 2024-10-16 18:19:19

很简单,OOP 原则是错误的。为什么这是一个漫长的讨论,会导致争论,并且可能不是本网站的主题。 :-)

在 Python 中没有私有属性,你无法保护它们,这从来都不是一个真正的问题。所以不要。简单的! :)

那么问题来了:是否应该有一个前导下划线。在你这里的例子中,你绝对不应该这样做。 Python 中的前导下划线是一种约定,用于表明某些内容是内部的,而不是 API 的一部分,并且您应该自行承担使用它的风险。显然这里的情况并非如此,但这是一个常见且有用的约定。

Quite simply, the OOP principles are wrong. Why this is is a long discussion which leads to flamewars and is probably off topic for this site. :-)

In Python there is not private attributes, you can't protect them, and this is never a real problem. So don't. Easy! :)

Then comes the question: Should you have a leading underscore or not. And in the example you have here you should definitely not. A leading underscore in Python is a convention to show that something is internal, and not a part of the API, and that you should use it on your own risk. This is obviously not the case here, but it's a common and useful convention.

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

self.attr = 0 #Done

您的方法并没有以任何方式将 _attr 设为私有,这只是有点混淆。

Python doesn't have public OR private attributes. All attributes are accessible to all code.

self.attr = 0 #Done

Your method isn't in any way making _attr private, it's just a bit of obfuscation.

凉城 2024-10-16 18:19:19

请参阅此链接:https://docs.python.org/2/tutorial/classes。 html

9.6。私有变量和类局部引用

Python 中不存在只能从对象内部访问的“私有”实例变量。然而,大多数 Python 代码都遵循一个约定:以下划线前缀的名称(例如 _spam)应被视为 API 的非公共部分(无论是函数、方法还是数据成员) 。它应被视为实施细节,如有更改,恕不另行通知。

由于类私有成员有一个有效的用例(即避免名称与子类定义的名称发生名称冲突),因此对这种称为名称修饰的机制的支持有限。 __spam 形式的任何标识符(至少两个前导下划线,最多一个尾随下划线)在文本上都会替换为 _classname__spam,其中 classname 是删除了前导下划线的当前类名称。这种修改的完成与标识符的语法位置无关,只要它出现在类的定义中即可。

See this link:https://docs.python.org/2/tutorial/classes.html

9.6. Private Variables and Class-local References

“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.

Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

网名女生简单气质 2024-10-16 18:19:19

正如其他人所说,Python 中的私有属性只是一种约定。 property 语法的使用应该用于属性绑定、修改或删除时的特殊处理。 Python 的美妙之处在于,您可以从使用普通属性绑定开始,例如,self.attr = 0,如果稍后您决定将 attr 的值限制为 < code>0 <= attr <=100,您可以将 attr 设为属性并定义一个方法来确保此条件为真,而无需更改任何用户代码。

As others have said, private attributes in Python are merely a convention. The use of property syntax should be used for special processing when attributes are bound, modified or deleted. The beauty of Python is that you can start off by just using normal attribute binding, e.g., self.attr = 0 and if at some later date you decide you want to restrict the value of attr to say 0 <= attr <=100, you can make attr a property and define a method to make sure this condition is true without ever having to change any user code.

千紇 2024-10-16 18:19:19

要将属性设为私有,您只需执行 self.__attr

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

To make an attribute private, you just have to do self.__attr

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
混吃等死 2024-10-16 18:19:19

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

In Python, unless you need special behavior out of an attribute, there's no need to hide it behind accessor methods. If an attribute is for internal use only, prepend it with an underscore.

话少情深 2024-10-16 18:19:19

属性的好处在于它们为您提供了一个非常酷的使用界面。有时,根据其他属性导出属性会很方便(例如,BMI 由体重和身高定义)。当然,界面的用户不必知道这一点。

我更喜欢这种方式,而不是像 Java ie 那样使用显式的 getter 和 setter。好多了。 :)

The nice thing about properties is that they given you a really cool interface to work with. Sometimes it's handy to derive a property based on some other (ie. BMI is defined by weight and height). The user of the interface doesn't have to know this of course.

I prefer this way over having explicit getters and setters like in Java ie. Way nicer. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文