为什么 Mypy 在 __init__ 中分配已在 class 正文中提示类型的属性时不给出键入错误?
Why is Mypy not giving a typing error when assigning attributes in __init__ that have been type hinted in the class body?
这是我的示例 python 文件
class Person:
name: str
age: int
def __init__(self, name, age):
self.name = name
self.age = age
p = Person(5, 5)
但是当我 运行 mypy test.py
我得到以下输出
$ mypy test.py
Success: no issues found in 1 source file
它不应该抱怨它试图将 5
分配给 name
变量并且我已经指出它应该是 str
类型
使用 reveal_type
可以为您提供有用的提示,说明为什么会发生这种情况:
class Person:
name: str
age: int
def __init__(self, name, age):
self.name = name
self.age = age
reveal_type(self.name)
p = Person(5, 5)
Output:
test_mypy1.py:8: note: Revealed type is 'Any'
test_mypy1.py:8: note: 'reveal_type' always outputs 'Any' in unchecked functions
所以原因是 Mypy 默认情况下根本不检查 __init__
方法的类型错误,因为你没有类型注释它。
TLDR:注释初始化程序,而不是字段:
class Person:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
p = Person(5, 5) # Argument 1 to "Person" has incompatible type "int"; expected "str"
查看此样式的 mypy Class Basics。
这里有两个问题:
MyPy 未检查完全未注释的 functions/methods:
MyPy: Function signatures and dynamic vs static typing
A function without type annotations is considered to be dynamically typed by mypy:
def greeting(name):
return 'Hello ' + name
By default, mypy will not type check dynamically typed functions. This means that with a few exceptions, mypy will not report any errors with regular unannotated Python.
如果您想消除此类漏掉的问题,请使用标志 --disallow-untyped-defs
or --check-untyped-defs
。
未注释的参数默认为Any
:
class Person:
name: str
age: int
def __init__(self, name, age: int) -> None:
self.name = name
reveal_type(name) # Revealed type is 'Any'
reveal_type(self.name) # Revealed type is 'builtins.str'
self.age = age
即使您的 __init__
被选中,它的参数也会采用并提供始终兼容的 Any
类型。
要直接解决这两个问题,请注释初始化参数而不是 class 插槽(如果两者重合)。如果 __init__
是自动生成的,则仅注释 class 插槽,例如通过 dataclasses.dataclass
或 typing.NamedTuple
,或者如果推理不够精确,则另外注释它们。
这是我的示例 python 文件
class Person:
name: str
age: int
def __init__(self, name, age):
self.name = name
self.age = age
p = Person(5, 5)
但是当我 运行 mypy test.py
我得到以下输出
$ mypy test.py
Success: no issues found in 1 source file
它不应该抱怨它试图将 5
分配给 name
变量并且我已经指出它应该是 str
使用 reveal_type
可以为您提供有用的提示,说明为什么会发生这种情况:
class Person:
name: str
age: int
def __init__(self, name, age):
self.name = name
self.age = age
reveal_type(self.name)
p = Person(5, 5)
Output:
test_mypy1.py:8: note: Revealed type is 'Any' test_mypy1.py:8: note: 'reveal_type' always outputs 'Any' in unchecked functions
所以原因是 Mypy 默认情况下根本不检查 __init__
方法的类型错误,因为你没有类型注释它。
TLDR:注释初始化程序,而不是字段:
class Person:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
p = Person(5, 5) # Argument 1 to "Person" has incompatible type "int"; expected "str"
查看此样式的 mypy Class Basics。
这里有两个问题:
MyPy 未检查完全未注释的 functions/methods:
MyPy: Function signatures and dynamic vs static typing
A function without type annotations is considered to be dynamically typed by mypy:
def greeting(name): return 'Hello ' + name
By default, mypy will not type check dynamically typed functions. This means that with a few exceptions, mypy will not report any errors with regular unannotated Python.
如果您想消除此类漏掉的问题,请使用标志
--disallow-untyped-defs
or--check-untyped-defs
。未注释的参数默认为
Any
:class Person: name: str age: int def __init__(self, name, age: int) -> None: self.name = name reveal_type(name) # Revealed type is 'Any' reveal_type(self.name) # Revealed type is 'builtins.str' self.age = age
即使您的
__init__
被选中,它的参数也会采用并提供始终兼容的Any
类型。
要直接解决这两个问题,请注释初始化参数而不是 class 插槽(如果两者重合)。如果 __init__
是自动生成的,则仅注释 class 插槽,例如通过 dataclasses.dataclass
或 typing.NamedTuple
,或者如果推理不够精确,则另外注释它们。