我正在用 Python 编写
dataclass
来收集 ArgumentParser.add_argument
所需的参数,但我在类型注释方面遇到了麻烦。
简化版:
from dataclasses import dataclass, KW_ONLY
from typing import Optional, TypeVar, Generic
T = TypeVar("T")
@dataclass
class CommandLineArgument(Generic[T]):
name_or_flags: str | tuple[str]
_: KW_ONLY
metavar: Optional[str] = None
type: Optional[type[T]] = None
default: Optional[T] = None
虽然
mypy
认为这是正确的(没有发现问题),但pytest
认为这是不对的。
请注意,当我在测试文件中导入 CommandLineArgument
时会发生这种情况。
如果这个类注释正确,为什么
pytest
会抱怨?
如果我将课程更改为:
@dataclass
class CommandLineArgument(Generic[T]):
name_or_flags: str | tuple[str]
_: KW_ONLY
metavar: Optional[str] = None
type: Optional[type[T]] = type
default: Optional[T] = None
那么
pytest
很高兴,但显然mypy
不高兴。
其他变体无法解决类似问题。
有没有办法让
pytest
和mypy
都对此感到高兴?
最简单的解决方案是在模块顶部添加
from __future__ import annotations
以停止在运行时评估类型注释。
这是您的最小可重现示例:
import typing as t
T = t.TypeVar("T")
class A(t.Generic[T]):
type: type[T] | None = None
这将在运行时失败,因为Python将在
type = None
的主体内分配A
,然后尝试在运行时评估type[T]
(变成None[T]
),并出现以下失败:
TypeError: 'NoneType' object is not subscriptable