You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 04:48:23