如有疑问,请将其“公开” - 我的意思是,不要添加任何内容来掩盖您的属性名称。如果您有一个具有某些内部价值的类,请不要理会它。而不是写:
class Stack(object):
def __init__(self):
self.__storage = [] # Too uptight
def push(self, value):
self.__storage.append(value)
默认写这个:
class Stack(object):
def __init__(self):
self.storage = [] # No mangling
def push(self, value):
self.storage.append(value)
这肯定是一种有争议的做事方式。 Python 新手讨厌它,甚至一些 Python 的老家伙也鄙视这个默认值 - 但无论如何它是默认值,所以我建议你遵循它,即使你觉得不舒服。
如果您真的想发送消息“不能碰这个!”对于您的用户,通常的方法是在变量前加上 one 下划线。这只是一个约定,但人们理解它并在处理此类事情时要格外小心:
class Stack(object):
def __init__(self):
self._storage = [] # This is ok, but Pythonistas use it to be relaxed about it
def push(self, value):
self._storage.append(value)
这对于避免属性名称和属性名称之间的冲突也很有用:
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
双下划线呢?好吧,我们主要使用双下划线魔术to avoid accidental overloading of methods and name conflicts with superclasses' attributes。如果您编写一个要多次扩展的类,这将非常有价值。
如果你想将它用于其他目的,你可以,但不常用也不推荐。
编辑:为什么会这样?好吧,通常的 Python 风格并不强调将事情私有化 - 相反!这有很多原因 - 其中大多数是有争议的......让我们看看其中的一些。
Python 有属性
今天,大多数 OO 语言使用相反的方法:不应该使用的不应该是可见的,所以属性应该是私有的。从理论上讲,这会产生更易于管理、耦合更少的类,因为没有人会鲁莽地更改对象的值。
然而,事情并非如此简单。例如,Java 类有许多只get 值和 只设置 值的setter。比方说,你需要七行代码来声明一个属性——Python 程序员会说这是不必要的复杂。此外,您可以编写大量代码来获取一个公共字段,因为您可以在实践中使用 getter 和 setter 更改其值。
那么为什么要遵循这个默认私有的政策呢?只需将您的属性默认公开即可。当然,这在 Java 中是有问题的,因为如果您决定为属性添加一些验证,则需要您全部更改:
person.age = age;
在你的代码中,让我们说,
person.setAge(age);
setAge() 是:
public void setAge(int age) {
if (age >= 0) {
this.age = age;
} else {
this.age = 0;
}
}
因此,在 Java(和其他语言)中,默认情况下无论如何都使用 getter 和 setter,因为它们编写起来可能很烦人,但如果您发现自己处于我所描述的情况,可以节省很多时间。
但是,您不需要在 Python 中执行此操作,因为 Python 具有属性。如果你有这个课程:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
...然后您决定验证年龄,您无需更改代码中的person.age = age 部分。只需添加一个属性(如下图)
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
假设你可以做到并且仍然使用person.age = age,你为什么要添加私有字段以及getter和setter?
(另请参阅Python is not Java 和this article about the harms of using getters and setters。)。
无论如何,一切都是可见的 - 试图隐藏会使您的工作复杂化
即使在具有私有属性的语言中,您也可以通过一些反射/内省库来访问它们。人们经常这样做,在框架中和解决紧急需求。问题在于,自省库只是一种复杂的方式,可以用公共属性来做一些事情。
由于 Python 是一种非常动态的语言,因此将这种负担添加到您的类中会适得其反。
无法看到问题 - 需要才能看到
对于 Python 达人来说,封装不是看不到类的内部,而是避免看它的可能性。封装是用户可以在不关心内部细节的情况下使用的组件的属性。如果您可以使用组件而不用担心它的实现,那么它就是封装的(在 Python 程序员看来)。
现在,如果您编写了一个类,您可以在不考虑实现细节的情况下使用它,如果您出于某种原因想要查看该类的内部没有问题。重点是:你的API要好,剩下的就是细节了。
圭多是这么说的
好吧,这没有争议:he said so, actually。 (寻找“开放式和服”。)
这就是文化
是的,有一些原因,但没有关键原因。这主要是 Python 编程的文化方面。坦率地说,它也可能是另一种方式——但事实并非如此。此外,您也可以轻松地反问:为什么某些语言默认使用私有属性?与 Python 实践的主要原因相同:因为这是这些语言的文化,每种选择都有优点和缺点。
既然已经存在这种文化,建议您遵循它。否则,当您在 Stack Overflow 中提出问题时,Python 程序员会告诉您从代码中删除 __,这会让您感到恼火:)