python - 在 Python 类中存储和断言类型

标签 python types pycharm warnings assert

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

我收到关于索引的警告:

enter image description here

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_typetype (这是正确的),但在 isinstance(value, self._data_type) 之后还假设 value 是一个 type (这是不正确的 - 它应该是 _data_type 类型)。因此,仅通过将 assert isinstance(...)data_typevalue 结合使用,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()

注意:我已经完全删除了断言。如果参数没有预期的类型或值,则 TypeErrorValueError 会提供更多信息。然而,在大多数情况下,文档和/或类型提示可以充分替代 Python 中的 assertTypeError(至少在使用 IDE 或使用 mypy 时)。

关于python - 在 Python 类中存储和断言类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58315765/

相关文章:

python - 从字符串列表中删除空白字符串值

php - PHP 数组可以容纳不同类型的项目吗?

c++ - const BYTE * 和 const LPBYTE

google-app-engine - 在 OS X 下的 PyCharm 上运行 GAE GCS,运行时错误 "No module named cloudstorage"

keyboard-shortcuts - 在 PyCharm 中打开资源搜索的快捷方式

javascript - Python POST 请求失败

python - 如何使用Python执行SSIS ETL包

c++ - 如何在 C++ 中编写整数和平凡类型之间的双向映射?

git - Pycharm,git : merge from master into branch

python - 如何使用 Python 3 循环导入