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

Python类型提示:如何让参数仅接收父类实例而非子类?

为类方法参数添加仅接受父类实例的类型提示

先看初始代码:

class Foo:
    @classmethod
    def bar(cls, baz):
        pass

class Egg(Foo):
    pass

egg = Egg()
egg.bar(Foo())

需求明确:给bar方法的baz参数添加类型提示,使其仅接受Foo类的实例,子类Egg的实例不允许传入。

尝试过的方案及问题

方案1:使用Self类型

修改后的代码:

from typing import Self

class Foo:
    @classmethod
    def bar(cls, baz: Self):
        pass

class Egg(Foo):
    pass

egg = Egg()
egg.bar(Foo())

用mypy静态检查时会报错:

Argument 1 to "bar" of "Foo" has incompatible type "Foo"; expected "Egg"  [arg-type]

原因是Self的语义是调用该方法的类的实例类型:当通过Egg实例调用bar时,Self会被解析为Egg,要求传入Egg实例,和我们需要的“仅接受Foo实例”完全相悖。

方案2:直接写baz: Foo

尝试将类型提示写成def bar(cls, baz: Foo):,但代码检查工具会提示undefined name 'Foo'——这是因为定义bar方法时,Foo类还未完成定义,属于前向引用问题。

解决方法

最优方案:使用from __future__ import annotations

Python 3.7及以上版本支持通过from __future__ import annotations让所有类型注解延迟求值,既解决前向引用问题,又无需手动给类名加引号:

from __future__ import annotations

class Foo:
    @classmethod
    def bar(cls, baz: Foo):
        pass

class Egg(Foo):
    pass

egg = Egg()
egg.bar(Foo())  # mypy检查通过,符合需求
egg.bar(Egg())  # mypy会报错,拦截子类实例传入

这种写法比手动写"Foo"更简洁清晰,是官方推荐的前向引用解决方案。

备选方案:使用typing.ForwardRef(不推荐)

如果不想启用未来特性,也可以用ForwardRef显式声明前向引用,但写法繁琐:

from typing import ForwardRef

FooType = ForwardRef('Foo')

class Foo:
    @classmethod
    def bar(cls, baz: FooType):
        pass

class Egg(Foo):
    pass

# Python 3.9及以下版本需手动解析前向引用
from typing import get_type_hints
get_type_hints(Foo.bar)

该方案仅适合特殊场景使用,远不如__future__ annotations便捷。

内容的提问来源于stack exchange,提问作者whoami

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 09:35:33