如何在子类方法中使用父类类方法生成子类实例并正确添加类型注解?
如何在子类方法中使用父类类方法生成子类实例并正确添加类型注解?
我来帮你搞定这个类型注解的问题,先拆解下你之前遇到的两个错误原因:
第一个方案里,你用了Self类型,但在copy方法里直接调用Subclass.from_dict(...)赋值给Self类型时,部分类型检查器(比如mypy)没法正确关联Subclass.from_dict的返回值和当前类的Self。其实换个写法,用self.from_dict代替直接调用类方法,就能让类型检查器准确识别返回的是当前子类的实例:
from typing import Self, Union class Superclass: @classmethod def from_dict(cls, dict_: dict[str, str]) -> Self: return cls(**dict_) class Subclass(Superclass): def __init__(self, name: Union[str, None] = None): self.name = name def copy(self) -> Self: # 改用self.from_dict,类型检查器能正确推断返回的是Subclass的Self return self.from_dict({'name': self.name})
这个写法在Python 3.11及以上版本可以正常工作,因为Self类型已经被官方支持了。
如果你需要兼容更早的Python版本,那我们可以优化你第二个方案的TypeVar写法。之前的错误是因为你定义的T绑定到Superclass,类型检查器会认为self可能是Superclass实例(它没有name属性),所以报错。我们可以给子类单独定义一个绑定到自身的TypeVar,明确self是子类实例:
from typing import Type, TypeVar, Union # 父类的TypeVar,绑定到Superclass SuperT = TypeVar('SuperT', bound='Superclass') class Superclass: @classmethod def from_dict(cls: Type[SuperT], dict_: dict[str, str]) -> SuperT: return cls(**dict_) # 子类的TypeVar,绑定到Subclass SubT = TypeVar('SubT', bound='Subclass') class Subclass(Superclass): def __init__(self, name: Union[str, None] = None): self.name = name def copy(self: SubT) -> SubT: return self.from_dict({'name': self.name})
这样类型检查器就知道self肯定是Subclass或者它的子类,自然能识别self.name是合法属性,同时from_dict也会返回正确的子类类型。
另外,如果你不想额外定义子类的TypeVar,也可以直接把copy方法的返回类型注解为Subclass,写法更直接,也能通过类型检查:
from typing import Type, TypeVar, Union T = TypeVar('T', bound='Superclass') class Superclass: @classmethod def from_dict(cls: Type[T], dict_: dict[str, str]) -> T: return cls(**dict_) class Subclass(Superclass): def __init__(self, name: Union[str, None] = None): self.name = name def copy(self) -> 'Subclass': return self.from_dict({'name': self.name})
备注:内容来源于stack exchange,提问作者Nils
相关产品推荐
相关产品推荐

