为什么 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)
产生相同的输出,即使它是包含 self 的 object.__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 定义
在对 x + y
求值期间,在后台 Python 调用 x.__add__(y)
。为什么 x.__add__(y)
和 int.__add__(x, y)
产生相同的输出,即使它是包含 self 的 object.__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__
.