Python 中的“public”或“private”属性?什么是最好的方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4555932/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"public" or "private" attribute in Python ? What is the best way?
提问by Sandro Munda
In Python, I have the following example class :
在 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
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.
如您所见,我有一个简单的“私有”属性“_attr”和一个可以访问它的属性。有很多代码可以声明一个简单的私有属性,我认为这样声明所有属性是不尊重“KISS”哲学的。
So, why not declare all my attributes as public attributes if I don't need a particular getter/setter/deleter ?
那么,如果我不需要特定的 getter/setter/deleter ,为什么不将我的所有属性声明为公共属性?
My answer will be : Because the principle of encapsulation (OOP) says otherwise!
我的回答会是:因为封装原理(OOP)另有说法!
What is the best way ?
什么是最好的方法 ?
采纳答案by Brian Clapper
Typically, Python code strives to adhere to the Uniform Access Principle. Specifically, the accepted approach is:
通常,Python 代码努力遵守统一访问原则。具体来说,公认的方法是:
- Expose your instance variables directly, allowing, for instance,
foo.x = 0, notfoo.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 = 0now invokesfoo.set_x(0).
- 直接公开您的实例变量,例如,允许
foo.x = 0, 不foo.set_x(0) - 如果您需要将访问包装在方法中,无论出于何种原因,请使用
@property,它保留了访问语义。也就是说,foo.x = 0现在调用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 conventionallyprivate. 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 preventsthem 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.
如果您使用双前导下划线(例如,__x),Python 会对名称进行一些混淆。然而,该变量仍然可以从类外部访问,通过其混淆的名称。这不是真正的私人。它只是有点……更不透明。并且有反对使用双下划线的有效论据;一方面,它会使调试更加困难。
回答by Tyler Eaves
Python doesn't have public OR private attributes. All attributes are accessible to all code.
Python 没有公共或私有属性。所有代码都可以访问所有属性。
self.attr = 0 #Done
Your method isn't in any way making _attr private, it's just a bit of obfuscation.
您的方法并没有以任何方式将 _attr 设为私有,只是有点混淆。
回答by Chris
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.
在 Python 中,除非您需要属性的特殊行为,否则无需将其隐藏在访问器方法之后。如果属性仅供内部使用,请在其前面加上下划线。
回答by Juho Veps?l?inen
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.
属性的好处在于它们为您提供了一个非常酷的界面来使用。有时根据其他属性推导出属性很方便(即 BMI 由体重和身高定义)。界面的用户当然不必知道这一点。
I prefer this way over having explicit getters and setters like in Java ie. Way nicer. :)
我更喜欢这种方式,而不是像 Java ie 那样具有显式的 getter 和 setter。好多了 :)
回答by Lennart Regebro
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. :-)
很简单,OOP 原则是错误的。为什么这是一个长时间的讨论,导致了激烈的争论,并且可能与本网站的主题无关。:-)
In Python there is not private attributes, you can't protect them, and this is never a real problem. So don't. Easy! :)
在 Python 中没有私有属性,你无法保护它们,这从来都不是一个真正的问题。所以不要。简单!:)
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 中的前导下划线是一种约定,表明某些内容是内部的,而不是 API 的一部分,您应该自担风险使用它。这显然不是这里的情况,但这是一个常见且有用的约定。
回答by Don O'Donnell
As others have said, private attributes in Python are merely a convention. The use of propertysyntax 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 = 0and if at some later date you decide you want to restrict the value of attr to say 0 <= attr <=100, you can make attra property and define a method to make sure this condition is true without ever having to change any user code.
正如其他人所说,Python 中的私有属性只是一种约定。property当属性被绑定、修改或删除时,应使用语法进行特殊处理。Python 的美妙之处在于,您可以从使用普通属性绑定开始,例如, self.attr = 0如果以后您决定将 attr 的值限制为 say 0 <= attr <=100,您可以创建attr一个属性并定义一个方法来确保此条件为真,无需更改任何用户代码。
回答by Ives Nikiema
To make an attribute private, you just have to do self.__attr
要将属性设为私有,您只需执行以下操作 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
回答by brannerchinese
The "dunder" (double underscore, __) prefix prevents access to attribute, except through accessors.
“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
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:
但是,您可以通过名称修改( _classname__attribute)访问此类属性,Python 在后台执行此操作:
>>> f._Foo__attr
0
>>> f.__getattribute__('_Foo__attr')
0
回答by W.Perrin
See this link:https://docs.python.org/2/tutorial/classes.html
请参阅此链接:https: //docs.python.org/2/tutorial/classes.html
9.6. Private Variables and Class-local References
9.6. 私有变量和类本地引用
“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.
Python 中不存在只能从对象内部访问的“私有”实例变量。但是,大多数 Python 代码都遵循一个约定:带有下划线前缀的名称(例如 _spam)应该被视为 API 的非公开部分(无论是函数、方法还是数据成员) . 它应被视为实施细节,如有更改,恕不另行通知。
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.
由于类私有成员有一个有效的用例(即避免名称与子类定义的名称的名称冲突),因此对这种称为名称修改的机制的支持有限。任何 __spam 形式的标识符(至少两个前导下划线,最多一个尾随下划线)在文本上替换为 _classname__spam,其中 classname 是当前类名,去掉了前导下划线。只要它出现在类的定义中,就可以不考虑标识符的句法位置来完成这种修改。

