为什么Python对某些内容使用双下划线?
我刚开始接触编程语言,Python是我学的第一门。我对Linux有一点了解,足够让我在暑假找到一份工作(我还在上高中),在工作中我有很多空闲时间,所以我在学习Python。
不过,有一件事让我困惑。像下面这样的表达式在Python中到底有什么不同呢?
x.__add__(y) <==> x+y
x.__getattribute__('foo') <==> x.foo
我知道方法是干什么的,也明白它们的作用,但我想问的是:上面那些双下划线的方法和看起来简单的那些有什么区别呢?
另外,我不介意听一些编程历史方面的讲解,实际上,我觉得了解这些很有用 :) 如果这些主要是Python的历史方面的内容,随便聊聊也可以。
7 个回答
当你在方法名前加上两个下划线(后面没有下划线)时,Python会应用一种叫做名称改编的规则。这是一种模仿其他面向对象语言(比如C++和Java)中private
关键字的方式。虽然这样的方法在技术上并不是完全私有的,但从外部访问起来会“难一些”。
如果一个方法前后都有两个下划线,那它就被认为是“内置”方法,也就是说,这些方法是由解释器使用的,通常是重载操作符或其他内置功能的具体实现。
这是Python的创造者在解释这件事:
... 我没有想出一种新的语法来处理特殊类型的类方法(比如初始化方法和析构方法),而是决定让用户通过实现一些特殊名称的方法来处理这些功能,比如
__init__
、__del__
等等。这种命名规则是从C语言中借来的,在C语言中,以下划线开头的标识符是由编译器保留的,通常有特殊的含义(例如,C预处理器中的宏__FILE__
)。
...
我还使用这种技术来允许用户自定义的类重新定义Python运算符的行为。正如之前提到的,Python是用C语言实现的,它使用函数指针表来实现内置对象的各种功能(例如,“获取属性”、“加法”和“调用”)。为了让这些功能能够在用户自定义的类中定义,我将各种函数指针映射到特殊的方法名称,比如
__getattr__
、__add__
和__call__
。这些名称与在C语言中实现新的Python对象时需要定义的函数指针表之间有直接的对应关系。
对于程序员来说,拥有更多的控制权是很重要的,所以应该有方法来定制一些行为。比如说,操作符重载(像 __add__
、__div__
、__ge__
等),属性访问(像 __getattribute__
、__getattr__
(这两个是不同的),__delattr__
等等)。在很多情况下,像操作符这样的语法和相应的方法是一一对应的。但在其他情况下,有一些特殊的过程,这些过程在某些时候会调用相应的方法。例如,__getattr__
只有在对象没有请求的属性时才会被调用,而 __getattribute__
如果没有实现或者抛出 AttributeError 时也会被调用。有些内容其实是比较高级的主题,深入到对象系统的内部,平时用到的机会不多。所以不需要把这些都学会,想了解的时候查查参考资料就可以了。说到参考资料,这里有一个链接。