如何为带默认值的参数设置正确的Python类型提示
解决带默认参数的泛型函数类型提示不兼容问题
问题场景
你尝试为以下代码添加类型提示,使用bound=Foo的TypeVar后,mypy报类型不兼容错误:
from typing import TypeVar class Foo: pass class FooBar(Foo): pass T = TypeVar("T", bound=Foo) def baz(type_: type[T] = Foo) -> T: return type_()
报错信息:
Incompatible default for argument "type_" (default has type "type[Foo]", argument has type "type[T]") [assignment] def baz(type_: type[T] = Foo) -> T: ^~~
报错原因
带bound=Foo的TypeVar表示T可以是Foo或其子类,但默认值Foo的类型是type[Foo],mypy无法确认这个默认值能匹配所有可能的T(比如当T是FooBar时,type[T]是type[FooBar],和type[Foo]不兼容),因此抛出类型不兼容的错误。
解决方案
方案1:Python 3.12+ 用TypeVar的default参数
Python 3.12为TypeVar新增了default参数,直接指定T的默认类型为Foo,就能让mypy识别默认值的兼容性:
from typing import TypeVar class Foo: pass class FooBar(Foo): pass # 指定T的默认类型为Foo T = TypeVar("T", bound=Foo, default=Foo) def baz(type_: type[T] = Foo) -> T: return type_()
方案2:兼容旧版本Python的函数重载
如果需要支持Python 3.11及以下版本,使用@overload定义两种调用场景:无参数时返回Foo,传入子类类型时返回对应子类实例:
from typing import TypeVar, overload class Foo: pass class FooBar(Foo): pass T = TypeVar("T", bound=Foo) # 无参数的重载情况 @overload def baz() -> Foo: ... # 传入类型参数的重载情况 @overload def baz(type_: type[T]) -> T: ... # 实际实现 def baz(type_: type[T] | type[Foo] = Foo) -> T | Foo: return type_()
这样mypy会正确推断:
- 调用
baz()时,返回类型为Foo - 调用
baz(FooBar)时,返回类型为FooBar
内容的提问来源于stack exchange,提问作者Oleg
相关产品推荐
相关产品推荐

