为什么 python 对某些东西使用两个下划线?
-
27-09-2019 - |
题
我对实际的编程语言相当陌生,Python 是我的第一个语言。我对 Linux 有点了解,足以用它找到一份暑期工作(我还在读高中),而且在工作中,我有很多空闲时间来学习 Python。
不过有一件事一直困扰着我。当你有这样的表达式时,Python 中到底有什么不同
x.__add__(y) <==> x+y
x.__getattribute__('foo') <==> x.foo
我知道方法的作用和用途,并且我了解它们的作用,但我的问题是:上面的那些双下划线方法与看起来更简单的等效方法有何不同?
P.S.,我不介意听关于编程历史的讲座,事实上,我发现了解它非常有用:)如果这些主要是 Python 的历史方面,请随意开始漫无目的。
解决方案
好,功率为程序员是很好的,所以应该有一种方法来定制行为。像运算符重载(__add__
,__div__
,__ge__
,...),属性访问(__getattribute__
,__getattr__
(这两个是不同的充),__delattr__
,......)等等。在许多情况下,如运营商,通常的语法映射1:1到各自的方法。在其他情况下,是在某些时候需要调用相应的方法的特别程序 - 例如,如果对象不具有请求的属性__getattr__
只调用和__getattribute__
未实现或凸起AttributeError的。他们中有些人是让你deeeeep到对象体系的胆量和很少需要真正高级的主题。所以没必要去学习所有这些,只是咨询,当你需要/想知道的参考。的参考,说到此处它是。
其他提示
下面是Python中的创建者解释它的:
...而不是设计一种新的语法 特殊类型的类方法(如 作为初始化和析构函数),我 决定这些功能可能是 通过简单地要求用户处理 实现具有特殊的方法 名称,如
__init__
,__del__
和 等等。这个命名约定是 从C,其中标识符取 用下划线开始被保留 由编译器,往往有特殊的 这意味着(例如,宏如 在C预处理__FILE__
)。
...
我也使用该技术,以允许 用户类重新定义的行为 Python的运营商。如从前那样 注意到,Python,在C语言实现,并 使用函数指针表来 实施的各种能力 内置对象(例如,“GET 属性”,‘添加’和‘通话’)。至 允许定义这些功能 在用户定义的类,我所映射的 各种函数指针特殊 方法的名字,如
__getattr__
,__add__
和__call__
。有一个 它们之间直接的对应关系 名称和功能表 指针人们必须时限定 实施新的Python对象用C
当你以两个下划线开始一个方法(并且没有尾随下划线)时,Python 的 名称修改 应用规则。这是一种松散模拟的方法 private
来自其他 OO 语言(例如 C++ 和 Java)的关键字。(即便如此,从技术上讲,该方法仍然不像 Java 和 C++ 方法那样是私有的,但从实例外部“更难获取”。)
具有两个前导和两个尾随下划线的方法被认为是“内置”方法,也就是说,它们由解释器使用,并且通常是重载运算符或其他内置功能的具体实现。
它们被用来指定Python解释应该在特定的情况下使用它们。
如,所述__add__
功能允许+
操作者工作的自定义类。否则,尝试添加时,你会得到某种没有定义的错误。
从历史上来看,前导下划线经常被用作指示给程序员这些名称的方法被认为是内部的封装/模块/库定义它们。在不提供私有命名空间的良好支持的语言,使用下划线是模拟一个约定。在Python中,当你定义了一个名为“__foo__”维护程序员从一些特别的东西是怎么回事这是不符合一个名为“富”方法发生的名字知道的方法。如果Python的已选择去使用“添加”作为内部方法重载“+”,那么你永远无法有没有造成很大的混乱的方法“添加”一类。下划线作为一个线索,一些神奇的会发生。
许多其他问题现在被标记为该问题的重复项,其中至少有两个问题询问 __spam__
方法被调用,或者约定被调用,并且现有的答案都没有涵盖这一点,所以:
实际上两者都没有正式名称。
许多开发人员非正式地将它们称为“dunder 方法”,即“Double UNDERscore”。
有些人使用术语“魔法方法”,但这在 dunder 方法、特殊方法(见下文)或两者之间的某种含义之间有些模糊。
那里 是 官方术语“特殊属性”,与 dunder 方法密切但不完全重叠。这 数据模型 参考文献中的章节从未完全解释什么是特殊属性,但基本思想是它至少是以下之一:
- 由解释器本身或其内置代码提供的属性,例如
__name__
在一个函数上。 - 属于解释器本身实现的协议一部分的属性,例如
__add__
为了+
运算符,或__getitem__
用于索引和切片。 - 允许解释器通过忽略实例并直接查找类来专门查找的属性,例如
__add__
再次。
大多数特殊属性是方法,但不是全部(例如, __name__
不是)。大多数使用“dunder”约定,但不是全部(例如, next
Python 2.x 中迭代器的方法)。
同时,大多数 dunder 方法都是特殊属性,但不是全部 - 特别是,stdlib 或外部库想要定义自己的以相同方式工作的协议并不罕见,例如 pickle
协议。
[猜测] Python 受到以下因素的影响 大陵五68, 吉多 可能使用 Algol68 阿姆斯特丹大学 其中 Algol68 有类似的“剥离制度”称为“引用剥离”。在 Algol68 中 运算符、类型和关键字 能 以不同的字体出现(通常是**大胆的**, 或者 __下划线__),在源代码文件中,这种字体是通过引号实现的,例如'abs'(引用类似于 '维基文本')
Algol68 ⇒ Python(运算符映射到成员函数)
- “和”⇒ __和__
- “或”⇒ __或__
- ‘不’⇒不
- ‘整’⇒ __trunc__
- ‘shl’⇒__lshift__
- ‘shr’⇒__rshift__
- 'upb' ⇒ __sizeof__
- ‘长’⇒__长__
- ‘int’⇒ __int__
- “真实”⇒ __float__
- ‘格式’⇒__格式__
- 'repr' ⇒ __repr__
- 'abs' ⇒ __abs__
- ‘减’⇒ __neg__
- ‘减’⇒ __sub__
- ‘加’⇒ __add__
- ‘倍’⇒ __mul__
- ‘mod’⇒__mod__
- 'div' ⇒ __truediv__
- ‘结束’⇒ __div__
- “向上”⇒ __pow__
- '我'⇒形象
- “是”⇒真实
- ‘conj’⇒共轭
在 Algol68 中,这些被称为 大胆的名字, ,例如 腹肌, ,但是 python 中的“under-under-abs” __abs__ 。
我的2分钱:所以有时——就像幽灵一样——当你将 Python 类剪切并粘贴到 wiki 中时,你会神奇地转世 Algol68 的类 大胆的 关键词。Ⅲ