我做了一个名为 的课程Emulate。它接受一个对象并接受该对象的属性。
class Emulate:
def __init__(self, obj):
for attr in dir(obj):
if attr != '__class__':
setattr(self, attr, getattr(obj, attr))
Run Code Online (Sandbox Code Playgroud)
现在,我想模拟整数1:
one = Emulate(1)
Run Code Online (Sandbox Code Playgroud)
/但是,我在尝试划分时无法使用:
print(one / 2)
Run Code Online (Sandbox Code Playgroud)
给出TypeError: unsupported operand type(s) for /: 'Emulate' and 'int'.
但是,如果我明确调用__truediv__:
print(one.__truediv__(2))
Run Code Online (Sandbox Code Playgroud)
它工作正常,0.5作为输出给出。
这里发生了什么?我以为x / y叫x.__truediv__(y).
注意:这不仅仅适用于除法。所有“魔法方法”都会发生这种情况。
魔术方法是在类上查找的,而不是在单个对象上查找的。您的Emulate类没有定义Emulate.__truediv__,而是添加一个实例属性,其值是在值method-wrapper上找到的int。
当您尝试使用 时one / 2,查找Emulate.__truediv__失败。
当您尝试使用 时one.__truediv__,实例属性的查找会成功并生成一个方法包装器,可以将其2作为其参数进行调用,从而给出观察到的结果。
您可以在生成的字节代码中看到这一点:
>>> dis.dis('print(one/2)')
1 0 LOAD_NAME 0 (print)
2 LOAD_NAME 1 (one)
4 LOAD_CONST 0 (2)
6 BINARY_TRUE_DIVIDE
8 CALL_FUNCTION 1
10 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
在这里,操作码BINARY_TRUE_DIVIDE负责尝试使用 引用的值的类型来查找必要的方法one。
>>> dis.dis('print(one.__truediv__(2))')
1 0 LOAD_NAME 0 (print)
2 LOAD_NAME 1 (one)
4 LOAD_METHOD 2 (__truediv__)
6 LOAD_CONST 0 (2)
8 CALL_METHOD 1
10 CALL_FUNCTION 1
12 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
在这里,对象上的显式方法查找one会生成您创建的实例属性的值__truediv__。