为何类上定义的@运算符重载与__getattr__无法直接生效?
问题:为什么类方法定义的
__matmul__无法通过@运算符调用? 问题重现
先看第一个示例,直接调用类方法正常,但使用@运算符执行失败:
class Foo: @classmethod def __matmul__(cls, other): return "abc" + other print(Foo.__matmul__("def")) # 正常运行,输出"abcdef" print(Foo @ "def") # 类型错误:不支持@运算符对'type'和'str'进行操作
__getattr__也存在同样的问题:
class Foo: @classmethod def __getattr__(cls, item): return "abc" + item print(Foo.__getattr__("xyz")) # 正常运行,输出"abcxyz" print(Foo.xyz) # 属性错误:类型对象'Foo'没有属性'xyz'
原因解析
Python中,类本身是元类的实例(默认元类是type)。当你对类对象(比如Foo)使用运算符或访问属性时,Python会去查找这个类的元类中定义的特殊方法,而不是类自身的类方法:
- 直接调用
Foo.__matmul__("def")是普通的类方法调用,Python会直接找到Foo类上的这个方法,所以能正常执行。 - 但使用
Foo @ "def"时,Python会去查找Foo的类型(也就是type)的__matmul__方法。默认的type元类没有实现这个方法,因此抛出类型错误。
同理,访问Foo.xyz时,当属性不存在,Python会尝试调用元类的__getattr__方法,而不是Foo类自身的类方法__getattr__,所以会触发属性错误。
解决方案:使用元类
将特殊方法定义在元类上,就能让类对象正常响应运算符或属性查找:
class MetaFoo(type): def __matmul__(cls, other): return "abc" + other class Foo(metaclass=MetaFoo): pass print(Foo.__matmul__("def")) # 正常运行,输出"abcdef" print(Foo @ "def") # 正常运行,输出"abcdef"
这是Python的bug吗?
不是,这是Python的设计逻辑:类对象的行为由其元类控制,类自身的类方法仅用于类的直接调用或实例的间接调用,而类对象的特殊方法(运算符重载、属性查找等)需要在元类中定义。
内容的提问来源于stack exchange,提问作者nick maxwell
相关产品推荐
相关产品推荐

