在Python中,对象名称前的单前导下划线和双前导下划线代表什么?
当前回答
下面是一个简单的示例,说明双下划线财产如何影响继承的类。因此,使用以下设置:
class parent(object):
__default = "parent"
def __init__(self, name=None):
self.default = name or self.__default
@property
def default(self):
return self.__default
@default.setter
def default(self, value):
self.__default = value
class child(parent):
__default = "child"
如果然后在python REPL中创建子实例,您将看到以下内容
child_a = child()
child_a.default # 'parent'
child_a._child__default # 'child'
child_a._parent__default # 'parent'
child_b = child("orphan")
## this will show
child_b.default # 'orphan'
child_a._child__default # 'child'
child_a._parent__default # 'orphan'
这对一些人来说可能很明显,但在一个复杂得多的环境中,这让我措手不及
其他回答
_foo:只是惯例。程序员指示变量是私有的(无论在Python中意味着什么)。__foo:这有真正的意义。解释器将此名称替换为_classname__foo,以确保该名称不会与其他类中的类似名称重叠。__foo__:只是惯例。Python系统使用不会与用户名冲突的名称的方法。
在Python世界中,没有其他形式的下划线有意义。此外,在这些约定中,类、变量、全局等之间没有区别。
根据Python中下划线的含义
单前导下划线(_var):表示名称仅供内部使用的命名约定。通常不由Python解释器强制执行(通配符导入除外),仅作为程序员的提示。单尾下划线(var_):按惯例使用,以避免与Python关键字的命名冲突。双前导下划线(__var):在类上下文中使用时触发名称更改。由Python解释器强制执行。双前导和尾随下划线(__var__):表示Python语言定义的特殊方法。避免为自己的属性使用此命名方案。单下划线(_):有时用作临时或不重要变量的名称(“不在乎”)。另外:Python REPL中最后一个表达式的结果。
.variable是半私有的,仅用于约定
.__variable通常被错误地认为是超级私有的,而它的实际含义只是为了命名mangle以防止意外访问[1]
.__variable__通常为内置方法或变量保留
您仍然可以访问__如果您非常想的话,可以对变量进行损坏。双下划线只是将变量命名为mangles或重命名为instance_类名__已损坏
例子:
class Test(object):
def __init__(self):
self.__a = 'a'
self._b = 'b'
>>> t = Test()
>>> t._b
'b'
t.b是可访问的,因为它仅按惯例隐藏
>>> t.__a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'
找不到t.__a,因为它由于名称损坏而不再存在
>>> t._Test__a
'a'
通过访问实例_className__variable而不仅仅是双下划线名称,您可以访问隐藏值
既然这么多人都在提到雷蒙德的谈话,我就把他说的话写下来,让事情变得简单一点:
双下划线的用意不是关于隐私。我们的意图是这样使用它类圆(对象):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。
了解_和_的事实非常容易;其他答案很好地表达了这一点。这种用法很难确定。
我是这样看的:
_
应用于指示函数不供公共使用,例如API。这和导入限制使其行为与c#中的内部行为非常相似。
__
应用于避免继承层次结构中的名称冲突,并避免后期绑定。很像c#中的private。
==>
如果你想表明某些东西不是供公众使用的,但它应该像受保护的用途一样。如果你想表明某些东西不是公共使用的,但它应该像私人使用一样。
这也是我非常喜欢的一句话:
问题是,一个类的作者可能会合理地认为“属性/方法名称应该是私有的,只能从内部访问这个类定义”,并使用__private约定,该类的用户可以创建合法需要的子类访问该名称。所以要么必须修改超类(这可能很困难或不可能),或者子类代码必须使用手动损坏的名称(这充其量是丑陋和脆弱的)。
但在我看来,如果没有IDE在重写方法时发出警告,那么如果意外地从基类重写了方法,查找错误可能需要一段时间。
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用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中获得所有直接子目录