PyCharm CE 2019.2.3 警告我有关一个类,该类存储了数据列表
以及值数据类型
。我试图将其简化为本质:
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.
进一步评论:
删除两个标记断言中的至少一个可以删除警告
令人困惑的是,针对
索引
出现警告,而这些断言引用值
添加额外的断言或类型提示文档字符串并没有消除我的警告
我的问题:我在存储和断言类型时做错了什么吗?该警告是否有任何原因?如果没有,您是否有一种方便的方法来删除它?
最佳答案
这里的问题有两个:
- PyCharm 在通过类型正确处理元类方面存在一些盲点(在撰写本文时)。因此,如果没有额外的“提示”,它目前无法推断出
value
的正确类型。 - 因为您使用
None
初始化了列表,PyCharm 将其视为包含 None 的列表。
让我们从元类问题开始:
您可以通过检查 data_type
是否是 type
(类的默认元类)的实例来检查它是否是一个类。然后检查值
是否是该类的实例。没关系。
但是 PyCharm 假设您的 data_type
是 type
(这是正确的),但在 isinstance(value, self._data_type)
之后还假设 value
是一个 type
(这是不正确的 - 它应该是 _data_type
类型)。因此,仅通过将 assert isinstance(...)
与 data_type
和 value
结合使用,PyCharm 将无法推导出 的正确类型>值
!
因此,这可能属于 PyCharm 中的 Bug 或缺失功能 - 或者 PyCharm 用于确定类型的任何库。
第二个问题是,通过使用 None
初始化 _data
,PyCharm 会将 _data
的类型推断为 List[None ]
(包含 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
会提供更多信息。然而,在大多数情况下,文档和/或类型提示可以充分替代 Python 中的 assert
和 TypeError
(至少在使用 IDE 或使用 mypy 时)。
关于python - 在 Python 类中存储和断言类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58315765/