Python名称混乱
在其他语言中,有助于生成更好代码的一般准则始终是尽可能隐藏所有内容。如果对变量应该是私有的还是受保护的有疑问,最好使用私有的 Python也是如此吗?我应该首先在所有东西上使用两个前导下划线,并根据需要减少隐藏(仅一个下划线) 如果约定只使用一个下划线,我还想知道其基本原理 这是我留下的评论。它解释了我为什么问这个问题,以及为什么我想知道为什么Python不同于其他语言: 我来自那些训练你认为一切都应该只在需要的时候公开的语言。理由是,这将减少依赖性,并使代码更安全地修改。Python以相反的方式做事情——从公开开始,到隐藏——对我来说很奇怪 如果有疑问,请将其保留为“public”——我的意思是,不要添加任何东西来模糊属性的名称。如果您有一个具有某些内部值的类,则不必担心它。而不是写:Python名称混乱,python,naming-conventions,Python,Naming Conventions,在其他语言中,有助于生成更好代码的一般准则始终是尽可能隐藏所有内容。如果对变量应该是私有的还是受保护的有疑问,最好使用私有的 Python也是如此吗?我应该首先在所有东西上使用两个前导下划线,并根据需要减少隐藏(仅一个下划线) 如果约定只使用一个下划线,我还想知道其基本原理 这是我留下的评论。它解释了我为什么问这个问题,以及为什么我想知道为什么Python不同于其他语言: 我来自那些训练你认为一切都应该只在需要的时候公开的语言。理由是,这将减少依赖性,并使代码更安全地修改。Python以相反的方
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家伙也鄙视这个默认值——但不管怎样,它是默认值,所以我真的建议你遵循它,即使你觉得不舒服
如果您确实想向用户发送消息“Can not touch this!”,通常的方法是在变量前面加一个下划线。这只是一个惯例,但人们理解它,在处理此类事情时要加倍小心:
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
那双下划线呢?嗯,主要使用双下划线魔术。如果您编写了一个需要多次扩展的类,那么它将非常有用
如果您想将其用于其他目的,您可以,但它既不常见也不推荐
编辑:为什么会这样?嗯,通常的Python风格并不强调将事情私有化——相反!这有很多原因,其中大多数都是有争议的。。。让我们看看其中的一些
Python具有属性
现在大多数OO语言使用相反的方法:不应该使用的东西不应该是可见的,所以属性应该是私有的。理论上,这将产生更易于管理、耦合更少的类,因为没有人会鲁莽地更改对象内部的值
然而,事情并非如此简单。例如,Java类确实有很多属性和getter,它们只获取值,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
代码片段。只需添加一个属性(如下所示)
如果您可以这样做,并且仍然使用person.age=age
,为什么要添加私有字段、getter和setter
(另请参见和。)
无论如何,一切都是可见的——试图隐藏只会使你的工作复杂化
即使在有私有属性的语言中,您也可以通过某种反射/内省库来访问它们。人们经常这样做,在框架内,为了解决紧急需求。问题在于,内省库只是一种很难实现公共属性的方法
由于Python是一种非常动态的语言,因此将这种负担添加到类中只会适得其反
问题是看不到-需要看到
对于Pythonista来说,封装不是看不到类的内部,而是避免看它的可能性。我的意思是,封装是组件的属性,它允许用户在不关心内部细节的情况下使用它。如果您可以使用一个组件而不必担心它的实现,那么它将被封装(在Python程序员看来)
现在,如果您以这样一种方式编写了类,您就可以使用它,而不必考虑实现细节,那么如果出于某种原因想查看类内部,就没有问题了。关键是:你的API应该是好的,剩下的就是细节
圭多是这么说的
嗯,这是没有争议的:。(寻找“开放和服”。)
这就是文化
是的,有一些原因,但没有关键原因。这主要是Python编程的文化方面。坦率地说,这也可能是另一种方式——但事实并非如此。另外,你也可以很容易地问另一个问题:为什么有些语言默认使用私有属性?与Python实践的主要原因相同:因为这是这些语言的文化,每种选择都有优点和缺点
既然这种文化已经存在,你最好遵循它。否则,当你问一个问题时,Python程序员会告诉你从代码中删除\uuu
,这会让你很恼火
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
lst = []
lst.append(1)
getattr(lst, 'append')(1)
class Demo:
__any_name = "__any_name"
__any_other_name_ = "__any_other_name_"
>>> [n for n in dir(Demo) if 'any' in n]
['_Demo__any_name', '_Demo__any_other_name_']
>>> Demo._Demo__any_name
'__any_name'
>>> Demo._Demo__any_other_name_
'__any_other_name_'
>>> class Foo(object):
... __foobar = None
... _foobaz = None
... __fooquux__ = None
...
>>> [name for name in dir(Foo) if 'foo' in name]
['_Foo__foobar', '__fooquux__', '_foobaz']
>>> Foo.__test = None
>>> Foo.__test
>>> Foo._Foo__test
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Foo' has no attribute '_Foo__test'
class Test:
def __init__(self):
self.__a = 'test1'
self._a = 'test2'
self.a = 'test3'
def change_value(self,value):
self.__a = value
return self.__a
testObj1 = Test()
valid_attributes = dir(testObj1)
print valid_attributes
['_Test__a', '__doc__', '__init__', '__module__', '_a', 'a',
'change_value']
testObj2 = Test()
print testObj2._Test__a
test1
testObj3 = Test()
print testObj3._a
test2
testObj4 = Test()
print testObj4.a
test3
class Demo:
__any_name = "__any_name"
__any_other_name_ = "__any_other_name_"
[n for n in dir(Demo) if 'any' in n] # GIVES OUTPUT AS ['_Demo__any_name',
# '_Demo__any_other_name_']