在 Python class 中存储和断言类型
Store and assert type in a Python class
PyCharm CE 2019.2.3 警告我 class,因为我存储了 list
数据以及值数据 type
。我试图将其还原为本质:
class Data:
def __init__(self, length, data_type):
assert isinstance(length, int) and length >= 0
assert isinstance(data_type, type) # commenting this line out removes the warning
self._data = [None] * length
self._data_type = data_type
def set_field(self, index, value):
assert isinstance(value, self._data_type) # commenting this line out removes the warning
assert isinstance(index, int)
self._data[index] = value
我在索引上收到警告:
Unexpected type(s):
(int, type)
Possible types:
(int, None)
(slice, Iterable[None])
Inspection Info: This inspection detects type errors in function call expressions. Due to dynamic dispatch and duck typing, this is possible in a limited but useful number of cases. Types of function parameters can be specified in docstrings or in Python 3 function annotation.
进一步评论:
删除两个标记断言中的至少一个会删除警告
令人困惑的是 index
出现警告,而这些断言指的是 value
添加额外的断言或类型提示文档字符串并没有为我删除警告
我的问题:我在存储和断言类型方面做错了吗?该警告是否有任何原因?如果没有,您是否看到了删除它的便捷方法?
这里的问题有两个:
- PyCharm 在通过打字正确处理元 classes 方面有一些盲点(在撰写本文时)。因此,如果没有额外的 "hints",它目前无法推断出
value
的正确类型。
- 因为您使用
None
初始化了您的列表 PyCharm 将其视为包含 Nones 的列表。
让我们从元class问题开始:
您通过检查 data_type
是否是 type
的实例(classes 的默认元 class)来检查 data_type
是否是 class。然后检查 value
是否是 class 的实例。没关系。
但是 PyCharm 假定您的 data_type
是 type
(这是正确的)但是在 isinstance(value, self._data_type)
之后它还假定 value
是type
(这是不正确的 - 它应该是 _data_type
类型)。因此,仅通过将 assert isinstance(...)
与 data_type
和 value
PyCharm 一起使用将无法推断出 value
!
的正确类型
所以这可能是 PyCharm 中的错误或缺失的功能 - 或者 PyCharm 用来确定类型的任何库。
第二个问题是,通过用 None
PyCharm 初始化 _data
将推断 _data
的类型为 List[None]
(包含的列表无)。
所以如果 PyCharm 推导出除 Any
(可以分配给任何东西)或 None
(这将是列表内容的预期类型)之外的任何东西 value
它将导致警告。
即使有:
def set_field(self, index, value):
assert isinstance(value, int) # <-- difference
assert isinstance(index, int)
self._data[index] = value
警告会来的。
此时你有两个选择:
- 忽略警告。
- 使用成熟的类型提示(如果目标 Python 版本允许)。
如果你想使用类型提示,你可以使用:
from typing import List, Optional, TypeVar, Generic, Type
T = TypeVar('T')
class Data(Generic[T]):
_data: List[Optional[T]]
_data_type: Type[T]
def __init__(self, length: int, data_type: Type[T]):
self._data = [None] * length
self._data_type = data_type
def set_field(self, index: int, value: T):
if isinstance(value, self._data_type):
self._data[index] = value
raise TypeError()
注意:我已经完全删除了断言。如果参数没有预期的类型或值,TypeError
或 ValueError
会提供更多信息。然而,在大多数情况下,文档 and/or 类型提示可以充分替换 assert
s 以及 Python 中的 TypeError
s(至少在使用 IDE 或使用 mypy 时).
PyCharm CE 2019.2.3 警告我 class,因为我存储了 list
数据以及值数据 type
。我试图将其还原为本质:
class Data:
def __init__(self, length, data_type):
assert isinstance(length, int) and length >= 0
assert isinstance(data_type, type) # commenting this line out removes the warning
self._data = [None] * length
self._data_type = data_type
def set_field(self, index, value):
assert isinstance(value, self._data_type) # commenting this line out removes the warning
assert isinstance(index, int)
self._data[index] = value
我在索引上收到警告:
Unexpected type(s):
(int, type)Possible types:
(int, None)
(slice, Iterable[None])Inspection Info: This inspection detects type errors in function call expressions. Due to dynamic dispatch and duck typing, this is possible in a limited but useful number of cases. Types of function parameters can be specified in docstrings or in Python 3 function annotation.
进一步评论:
删除两个标记断言中的至少一个会删除警告
令人困惑的是
index
出现警告,而这些断言指的是value
添加额外的断言或类型提示文档字符串并没有为我删除警告
我的问题:我在存储和断言类型方面做错了吗?该警告是否有任何原因?如果没有,您是否看到了删除它的便捷方法?
这里的问题有两个:
- PyCharm 在通过打字正确处理元 classes 方面有一些盲点(在撰写本文时)。因此,如果没有额外的 "hints",它目前无法推断出
value
的正确类型。 - 因为您使用
None
初始化了您的列表 PyCharm 将其视为包含 Nones 的列表。
让我们从元class问题开始:
您通过检查 data_type
是否是 type
的实例(classes 的默认元 class)来检查 data_type
是否是 class。然后检查 value
是否是 class 的实例。没关系。
但是 PyCharm 假定您的 data_type
是 type
(这是正确的)但是在 isinstance(value, self._data_type)
之后它还假定 value
是type
(这是不正确的 - 它应该是 _data_type
类型)。因此,仅通过将 assert isinstance(...)
与 data_type
和 value
PyCharm 一起使用将无法推断出 value
!
所以这可能是 PyCharm 中的错误或缺失的功能 - 或者 PyCharm 用来确定类型的任何库。
第二个问题是,通过用 None
PyCharm 初始化 _data
将推断 _data
的类型为 List[None]
(包含的列表无)。
所以如果 PyCharm 推导出除 Any
(可以分配给任何东西)或 None
(这将是列表内容的预期类型)之外的任何东西 value
它将导致警告。
即使有:
def set_field(self, index, value):
assert isinstance(value, int) # <-- difference
assert isinstance(index, int)
self._data[index] = value
警告会来的。
此时你有两个选择:
- 忽略警告。
- 使用成熟的类型提示(如果目标 Python 版本允许)。
如果你想使用类型提示,你可以使用:
from typing import List, Optional, TypeVar, Generic, Type
T = TypeVar('T')
class Data(Generic[T]):
_data: List[Optional[T]]
_data_type: Type[T]
def __init__(self, length: int, data_type: Type[T]):
self._data = [None] * length
self._data_type = data_type
def set_field(self, index: int, value: T):
if isinstance(value, self._data_type):
self._data[index] = value
raise TypeError()
注意:我已经完全删除了断言。如果参数没有预期的类型或值,TypeError
或 ValueError
会提供更多信息。然而,在大多数情况下,文档 and/or 类型提示可以充分替换 assert
s 以及 Python 中的 TypeError
s(至少在使用 IDE 或使用 mypy 时).