如何在Python Typing中指定F-界多态(引用子类类型)
解决带类型安全的可复制接口类型报错问题
问题场景
我想实现一个带类型安全的可复制接口,写出了以下代码:
from typing import TypeVar, Generic from abc import abstractmethod T = TypeVar( "T", bound="Copyable['T']" ) class Copyable( Generic[T] ): @abstractmethod def Copy( self ) -> T: pass class Example( Copyable[ 'Example' ] ): def Copy( self ) -> 'Example': return Example()
遇到的报错
- Pylance提示:
TypeVar bound type cannot be generic - MyPy提示:
error: Type variable "script.example.T" is unbound
额外说明
下面这种写法不算解决方案,因为复制Example类型的对象后,返回类型会被降级为Copyable,丢失了具体的类型信息:
class Copyable: @abstractmethod def Copy( self ) -> Copyable: pass class Example( Copyable ): def Copy( self ) -> Copyable: return Example()
上下文
我需要把这个接口用到一个接收回调函数的类里,回调函数的第一个参数是类本身的实例。这个类支持继承,如果回调函数的类型定义成Callback[ [ Baseclass ], None ],用派生类的时候就没法直接访问派生类的方法,除非手动做类型转换。
解决方案
方案1:用Python 3.11+的Self类型(推荐)
Python 3.11新增了typing.Self,可以直接表示当前类的实例类型,写法简单还能通过类型检查:
from typing import Self from abc import abstractmethod class Copyable: @abstractmethod def Copy(self) -> Self: pass class Example(Copyable): def Copy(self) -> Self: return Example()
方案2:调整TypeVar绑定逻辑(兼容旧版Python)
如果要兼容Python 3.11之前的版本,可以修改TypeVar的绑定方式,避免在bound里用泛型类型:
from typing import TypeVar, Generic from abc import abstractmethod # 先声明TypeVar,绑定非泛型的Copyable名称 T = TypeVar("T", bound="Copyable") class Copyable(Generic[T]): @abstractmethod def Copy(self) -> T: pass class Example(Copyable["Example"]): def Copy(self) -> "Example": return Example()
这样写能让Pylance和MyPy都通过检查,同时保留类型信息——调用Example().Copy()时,类型检查器会识别返回值是Example类型,不会降级成Copyable。
内容的提问来源于stack exchange,提问作者Sam Coutteau
相关产品推荐
相关产品推荐

