我觉得这段代码应该可以工作,但是第二个表达式失败了。这是为什么?
class Foo:
@classmethod
def __matmul__(cls, other):
return "abc" + other
print(Foo.__matmul__("def")) # OK
print(Foo @ "def") # TypeError: unsupported operand type(s) for @: 'type' and 'str'
同样适用于
__getattr__
:
class Foo:
@classmethod
def __getattr__(cls, item):
return "abc" + item
print(Foo.__getattr__("xyz")) # OK
print(Foo.xyz) # AttributeError: type object 'Foo' has no attribute 'xyz'
解决方案是使用元类
class MetaFoo(type):
def __matmul__(cls, other):
return "abc" + other
class Foo(metaclass=MetaFoo):
pass
print(Foo.__matmul__("def")) # OK
print(Foo @ "def") # OK
这是 (C)Python 中的错误吗?
要明确的是,问题是为什么在没有元类的情况下
print(Foo @ "def")
在第一个示例中不起作用?
您观察到的行为不是 Python 中的错误,而是运算符重载和类方法设计在 Python 中工作方式的结果。
在第一个示例中,您已将
__matmul__
定义为类方法。虽然这允许直接在类上调用它 (Foo.__matmul__("def")
),但它不允许对类本身使用 @
运算符。在Python中,当您使用像@
这样的运算符时,Python会在左操作数的类中查找相应的特殊方法(在本例中为__matmul__
)。由于 Foo
是 type
的实例(因为 Python 中的类是 type
的实例),Python 在 __matmul__
上查找 type
,而不是在 Foo
上。