在Python中,对象名称前的单前导下划线和双前导下划线代表什么?
当前回答
_var:python中带前导单下划线的变量是经典变量,旨在通知使用代码的其他人该变量应保留供内部使用。它们与经典变量有一点不同:在对定义它们的对象/模块进行通配符导入时,不会导入它们(定义__all__变量时除外)。如:#foo.pyvar=“var”_var=“_var”#巴.py从foo导入*print(dir())#已定义对象的列表,包含“var”但不包含“_var”打印(var)#varprint(_var)#name错误:未定义名称“_var”_:单下划线是前导单下划线变量的特殊情况。按照惯例,它被用作垃圾变量,以存储一个不打算稍后访问的值。它也不会通过通配符导入来导入。这个for循环打印“我不能在课堂上讲话”10次,并且永远不需要访问_变量。对于范围(10)内的_:打印(“我不能在课堂上讲话”)var_:单尾随下划线变量。它们是传统的变量,用于避免与Python关键字冲突。如:class_=“MyClassName”__var:双前导下划线变量(至少两个前导下划线,最多一个尾随下划线)。当用作类属性(变量和方法)时,这些变量会受到名称篡改:在类之外,python会将属性重命名为_<class_name>__<attribute_name>。例子:类MyClass:__an_attribute=“属性值”my_class=我的类()print(my_class.MyClass__an_attribute)#“属性值”print(my_class.__an_attribute)#AttributeError:“MyClass”对象没有属性“__an_aattribute”当用作类外部的变量时,它们的行为类似于单前导下划线变量。__var__:双前导和尾随下划线变量(至少两个前导和尾随底线)。也称为dunders。python使用此命名约定在内部定义变量。避免使用此约定来防止python更新可能产生的名称冲突。Dunder变量的行为类似于单前导下划线变量:它们在类中使用时不受名称篡改的影响,但不会在通配符导入中导入。
其他回答
既然这么多人都在提到雷蒙德的谈话,我就把他说的话写下来,让事情变得简单一点:
双下划线的用意不是关于隐私。我们的意图是这样使用它类圆(对象):def__init__(自身,半径):self.radius=半径定义区域(自身):p=自身__周长()r=p/math.pi/2.0返回math.pi*r**2.0定义周长(自身):return 2.0*math.pi*self.radius__周界=周界#本地参考等级轮胎(圆形):定义周长(自身):返回圆周长(自身)*1.25这实际上是隐私的反面,都是关于自由的。它使您的子类可以自由覆盖任何一个方法,而不破坏其他方法。
假设您没有在Circle中保留周界的本地参考。现在,派生类Tire覆盖了周长的实现,而不接触面积。当您调用Tire(5).area()时,理论上它应该仍然使用Circle.perimeter进行计算,但实际上它使用的是Tire.perimet,这不是预期的行为。这就是为什么我们需要Circle的本地参考。
但为什么用周长代替周长?因为_perimeter仍然给派生类重写的机会:
class Tire(Circle):
def perimeter(self):
return Circle.perimeter(self) * 1.25
_perimeter = perimeter
双下划线具有名称损坏,因此父类中的本地引用在派生类中被重写的可能性很小。因此“使您的子类可以自由覆盖任何一个方法而不破坏其他方法”。
如果您的类不会被继承,或者方法重写不会破坏任何东西,那么您就不需要__double_leading_underscore。
你的问题很好,不仅仅是关于方法。模块中的函数和对象通常也以一个下划线作为前缀,也可以以两个下划线作为后缀。
例如,__double_underscore名称在模块中不会被篡改。如果从一个模块(从模块导入*)导入所有名称,则不会导入以一个(或多个)下划线开头的名称,也不会导入帮助(模块)中显示的名称。
如果真的想让变量成为只读的,IMHO最好的方法就是使用property(),只传递getter。有了property()我们可以完全控制数据。
class PrivateVarC(object):
def get_x(self):
pass
def set_x(self, val):
pass
rwvar = property(get_p, set_p)
ronly = property(get_p)
我知道OP问了一个稍有不同的问题,但由于我发现另一个问题是“如何设置私有变量”,标记为与此重复,所以我想在这里添加此附加信息。
_foo:只是惯例。程序员指示变量是私有的(无论在Python中意味着什么)。__foo:这有真正的意义。解释器将此名称替换为_classname__foo,以确保该名称不会与其他类中的类似名称重叠。__foo__:只是惯例。Python系统使用不会与用户名冲突的名称的方法。
在Python世界中,没有其他形式的下划线有意义。此外,在这些约定中,类、变量、全局等之间没有区别。
开头有一个下划线:
Python没有真正的私有方法。相反,方法或属性名称开头的一个下划线表示您不应该访问此方法,因为它不是API的一部分。
class BaseForm(StrAndUnicode):
def _get_errors(self):
"Returns an ErrorDict for the data provided for the form"
if self._errors is None:
self.full_clean()
return self._errors
errors = property(_get_errors)
(此代码片段取自django源代码:django/forms/forms.py)。在这段代码中,error是一个公共属性,但此属性调用的方法_get_errors是“私有”的,因此您不应该访问它。
开头有两个下划线:
这会引起很多混乱。它不应用于创建私有方法。应该使用它来避免方法被子类重写或意外访问。让我们看一个例子:
class A(object):
def __test(self):
print "I'm a test method in class A"
def test(self):
self.__test()
a = A()
a.test()
# a.__test() # This fails with an AttributeError
a._A__test() # Works! We can access the mangled name directly!
输出:
$ python test.py
I'm test method in class A
I'm test method in class A
现在创建一个子类B并为__test方法进行定制
class B(A):
def __test(self):
print "I'm test method in class B"
b = B()
b.test()
输出将是。。。。
$ python test.py
I'm test method in class A
正如我们所看到的,B.test()并没有像我们预期的那样调用B.__test()方法。但事实上,这是__的正确行为。名为__test()的两个方法会自动重命名(损坏)为_A__test()和_B__test(。当你创建一个以__开头的方法时,这意味着你不希望任何人能够覆盖它,你只想从它自己的类内部访问它。
开头和结尾有两个下划线:
当我们看到像__this___这样的方法时,不要调用它。这是python要调用的方法,而不是您。让我们来看看:
>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11
>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60
总是有一个运算符或本机函数调用这些神奇的方法。有时它只是在特定情况下python调用的钩子。例如,在调用__new__()构建实例后创建对象时调用__init__()。。。
让我们举个例子。。。
class FalseCalculator(object):
def __init__(self, number):
self.number = number
def __add__(self, number):
return self.number - number
def __sub__(self, number):
return self.number + number
number = FalseCalculator(20)
print number + 10 # 10
print number - 20 # 40
有关详细信息,请参阅[PEP-8指南][1]。有关更多神奇的方法,请参阅[本PDF][2]。[1]: https://www.python.org/dev/peps/pep-0008/#method-名称和实例变量[2] http://github.com/RafeKettler/magicmethods/blob/master/magicmethods.pdf
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录