using Python 3.11 and Mypy 1.7.

我正在try 正确地键入hint方法,该方法接受一个类作为参数,带有一个默认值,并返回该类的一个实例.作为参数传递的类必须是特定基类的子类. 我该怎么做呢? 我试着这样用type variable with upper bound:

from typing import TypeVar


class BaseClass: pass
class ImplClass(BaseClass): pass

T = TypeVar("T", bound=BaseClass)

def method(return_type: type[T] = ImplClass) -> T:
    return return_type()

但Mypy抱怨道:

scratch_10.py: note: In function "method":
scratch_10.py:9:35: error: Incompatible default for argument "return_type" (default has type "type[ImplClass]", argument has type "type[T]")  [assignment]
    def method(return_type: type[T] = ImplClass) -> T:
                                      ^~~~~~~~~

但据我所知,这个错误是错误的,因为缺省的ImplClassBaseClass的子类,这是T的上界,所以它尊重类型约束.

请注意,移除上限值无济于事:

T = TypeVar("T") #no upperbound this time
def method(return_type: type[T] = ImplClass) -> T:
    return return_type()

(相同的错误消息)

但删除缺省值并以ImplClass作为参数显式调用method的效果没有任何问题:

def method(return_type: type[T]) -> T: # no default value this time
    return return_type()

method(ImplClass)

成功,在1个源文件中未发现问题

所以我不明白为什么mypy抱怨缺省值,而不是抱怨具有完全相同的值的实际参数.这是mypy的假阳性,还是我做错了什么?

推荐答案

这是mypy的一个已知限制.有关讨论,请参阅GitHub问题#8739 - mypy reporting error with default value for typevar#3737 - Unable to specify a default value for a generic parameter.

您可以使用typing.overload来单独注释使用缺省值的情况:

from typing import TypeVar, overload


class BaseClass: pass
class ImplClass(BaseClass): pass

T = TypeVar("T", bound=BaseClass)


@overload
def method() -> ImplClass:
    ...
     
@overload    
def method(return_type: type[T]) -> T:
    ...

def method(return_type=ImplClass):
    return return_type()
    

reveal_type(method())           # ok: ImplClass
reveal_type(method(BaseClass))  # ok: BaseClass
reveal_type(method(ImplClass))  # ok: ImplClass
# reveal_type(method(int))      # error

这将使用mypy(Python3.12,v1.7.1)通过类型判断,并输出

main.py:23: note: Revealed type is "__main__.ImplClass"
main.py:24: note: Revealed type is "__main__.BaseClass"
main.py:25: note: Revealed type is "__main__.ImplClass"
Success: no issues found in 1 source file

Try it yourself online.

Python相关问答推荐

从不规则形状区域返回使用openCV跟踪的对象的着陆位置

在Python中根据id填写年份系列

customtkinter中使用的这个小部件的名称是什么

如何在矩阵上并行化简单循环?

这家einsum运营在做什么?E = NP.einsum(aj,kl-il,A,B)

Python:记录而不是在文件中写入询问在多文件项目中记录的最佳实践

NumPy中的右矩阵划分,还有比NP.linalg.inv()更好的方法吗?

Pandas 在时间序列中设定频率

在Python中为变量的缺失值创建虚拟值

如果索引不存在,pandas系列将通过索引获取值,并填充值

Python中MongoDB的BSON时间戳

如何使用SubProcess/Shell从Python脚本中调用具有几个带有html标签的参数的Perl脚本?

TARete错误:类型对象任务没有属性模型'

PywinAuto在Windows 11上引发了Memory错误,但在Windows 10上未引发

将图像拖到另一个图像

Python中绕y轴曲线的旋转

我想一列Panadas的Rashrame,这是一个URL,我保存为CSV,可以直接点击

如何使用Pandas DataFrame按日期和项目汇总计数作为列标题

Django RawSQL注释字段

在pandas数据框中计算相对体积比指标,并添加指标值作为新列