理解Python中的算术运算符
我目前的理解是,像 '+' 和 '-' 这样的算术运算符其实是一种特殊的方法,属于整数类。它们看起来有点不同,因为你不需要像这样写算术操作:x.__add__(y)
,但实际上,当你写 x + y
时,背后就是在执行这个操作。
我第一个问题是:我这样理解对吗?
我的第二个问题是:在 __add__
方法中发生了什么?我在任何文档中都找不到相关信息。我想理解这个过程是如何避免无限回归的,因为我只能想象这个方法像这样:
def __add__(a,b):
return a + b
但当然,你并没有解释 '+' 是怎么回事,这就导致了无限回归。
我希望我的问题清楚,因为我脑海中有点模糊。基本上,我想对 Python 的基础知识有一个好的理解。(也许其他语言也是?)
5 个回答
你说得对:
class Test(object):
def __add__(self, other):
return self + other
这样会引发问题:
>>> a = Test()
>>> b = Test()
>>> a + b
Traceback (most recent call last):
File "<pyshell#30>", line 1, in <module>
a + b
File "<pyshell#27>", line 4, in __add__
return self + other
...
File "<pyshell#27>", line 4, in __add__
return self + other
RuntimeError: maximum recursion depth exceeded
不过,类的加法并不是这样实现的。通常,你会把实例的加法定义为对属性的加法,比如:
class Money(object):
def __init__(self, amount):
self.amount = amount
def __add__(self, other):
return Money(self.amount + other.amount)
在 __add__
方法中对 amount
属性的加法,具体取决于 amount
的类型是怎么实现 __add__
的,但因为:
>>> 1 + 2
3
这样工作,所以你可以假设这不是“乌龟”一直到底的情况!
其实,+
这个符号是一个运算符,它是任何编程语言的基本组成部分。Python和大多数其他面向对象的编程语言允许你为自定义的类定义+
运算符。这是通过在你新创建的类里定义__add__
方法来实现的。
希望这能帮助你更好地理解。
对于数字类型来说,__add__
这个方法很可能是用底层的原生代码实现的,所以出现无限递归的情况几乎不可能。因此,你写的返回值a+b实际上是调用了底层的原生代码。
关于 __add__(a, b)
这个数字相加的功能:
我不是Python专家,但我猜这个操作会调用一些底层的代码来实际进行计算。这个底层代码是用你正在使用的Python版本所写的语言实现的。例如,如果你使用的是CPython,那么它会调用一个用C语言写的(已经编译好的)函数来完成这个操作。
确实,Python会把+
和-
这两个操作符转换成.__add__()
的调用,但它也会在第二个操作数上使用__radd__()
方法来处理反向操作。这让自定义类型在和标准类型一起使用时,可以插入自己的逻辑。
当你执行x + y
时,发生的事情是:
- 如果
y
是x
的子类,首先会尝试y.__radd__(x)
;这样可以让你用更具体的类来覆盖默认行为。 - 接着尝试
x.__add__(y)
,如果成功了,那就是这个表达式的结果。如果这个调用返回了特殊的NotImplemented
,就继续到下一步。 - 再尝试
y.__radd__(x)
;如果成功了,那就是这个表达式的结果。如果它也返回NotImplemented
,那么就会抛出一个TypeError
异常,表示操作失败。
因为Python内置类型是用C语言实现的,所以__add__
的实际实现不会引发竞争条件。int.__add__
的C代码处理的是C整数值和C语言的+
操作符,实际上就是把数字加在一起。
在自定义的Python对象中,通常是通过对属性或其他值进行相加来表达加法:
def __add__(self, other):
if not isinstance(other, type(self)):
return NotImplemented # cannot handle other types
return type(self)(self.foobar + other.foobar + self.summation_margin)
这些属性可能有自己的__add__
实现。