Python中@multimethod与Self结合使用的方法及相关类型错误排查
Python中@multimethod与Self结合使用的方法及相关类型错误排查
看起来你遇到的是multimethod库和typing.Self类型注解的兼容性问题,我来帮你拆解原因和解决办法。
错误原因分析
你看到的TypeError: typing.Self cannot be used with issubclass(),本质是两个点的冲突:
typing.Self是Python 3.11引入的特殊类型提示,它的作用是在类定义内部指代当前类,但在类还没完全定义完成时,Self并没有绑定到实际的Name类对象上,只是一个占位的特殊标记。multimethod库在注册多方法时,会通过issubclass()检查类型的继承关系来确定方法优先级,但Self并不是能直接用于issubclass()的常规类,所以触发了这个错误。
解决办法
有几个可行的方案,你可以根据场景选择:
方案1:用字符串前向引用代替Self
在类定义完成前,用类名字符串"Name"代替Self,这样multimethod会等类完全定义后再解析这个类型:
from enum import Enum, auto from typing import List from multimethod import multimethod class Name: __id: list[str] def __new__(cls, id: list[str]): # 顺便修正你__new__的写法:__new__第一个参数是cls,且要返回创建的实例 instance = super().__new__(cls) instance.__id = id return instance @multimethod def prefix(self, other: "Name") -> "Name": return self.prefix(other.__id) @multimethod def prefix(self, prefix: List[str]) -> "Name": return Name(prefix + self.__id) @multimethod def postfix(self, postfix: List[str]) -> "Name": return Name(self.__id + postfix)
方案2:启用延迟类型注解求值
Python 3.7+支持通过__future__导入annotations,让类型注解以字符串形式存储,直到运行时才解析,这样multimethod就不会在类定义阶段直接处理Self:
from __future__ import annotations from enum import Enum, auto from typing import Self, List from multimethod import multimethod class Name: __id: list[str] def __new__(cls, id: list[str]): instance = super().__new__(cls) instance.__id = id return instance @multimethod def prefix(self, other: Self) -> Self: return self.prefix(other.__id) @multimethod def prefix(self, prefix: List[str]) -> Self: return Name(prefix + self.__id) @multimethod def postfix(self, postfix: List[str]) -> Self: return Name(self.__id + postfix)
这个方案的好处是你能继续用Self这个更直观的注解,不用替换成字符串。
方案3:升级multimethod库到最新版本
部分较新的multimethod版本已经兼容了Self类型,你可以先尝试升级库:
pip install --upgrade multimethod
如果升级后错误消失,说明是旧版本的兼容性问题,直接用新版本即可。
验证修改
修改后可以简单测试功能是否正常:
n1 = Name(["a", "b"]) n2 = Name(["x", "y"]) print(n1.prefix(n2).__id) # 预期输出:['x', 'y', 'a', 'b'] print(n1.prefix(["pre"]).__id) # 预期输出:['pre', 'a', 'b'] print(n1.postfix(["post"]).__id) # 预期输出:['a', 'b', 'post']
备注:内容来源于stack exchange,提问作者Cherry
相关产品推荐
相关产品推荐

