为什么 x.__add__(y) 和 int.__add__(x, y) 产生相同的输出?

Why do both x.__add__(y) and int.__add__(x, y) produce the same output?

在对 x + y 求值期间,在后台 Python 调用 x.__add__(y)。为什么 x.__add__(y)int.__add__(x, y) 产生相同的输出,即使它是包含 selfobject.__add__(self, other)

要回答这个问题,在一般情况下他们不会这样做,但在实践中他们会这样做,因为您没有看到方法在实例级别被覆盖。

通常情况下,调用x.method(y)会在调用前将class中的函数对象method绑定到实例x。结果相当于 type(x).method.__get__(x, type(x))(y).

对于普通函数,描述符 __get__ 操作 returns 一个绑定方法对象,它大约是一个部分函数对象,第一个参数作为 self 归档。然后你用所有其他参数调用它。

但是如果你有这样的事情怎么办:

class C:
    def method(self, y):
        return y + 1

def method2(self, y):
    return y + 2

x = C()
x.method = method2.__get__(x, C)

print(C.method(x, 2))  # 3
print(x.method(2))     # 4

由于函数对象是非数据描述符,x.method会调用实例字典中预先绑定的方法对象,而不是绑定到class字典中的描述符。

int 是一个不可变的 class,主要在 C 中实现,您不能为其分配实例方法。所以如果type(x) == int,那么x.__add__(y)等价于int.__add__.__get__(x, int)(y),在功能上等价于int.__add__(x, y).

这里需要注意的是,使用实现运算符的双下划线方法具有特殊行为。 Python 将语句 x + y 优化为 type(x).__add__(x, y),而不是 x.__add__(y)。如此处所示,这节省了几个命名空间查找和方法绑定操作。结果是,如果您要在实例上重写 __add__,实例方法将被忽略以支持 __add__.

的 class 定义