Python 使用省略号或无 + 浮点类型提示未分配属性

Posted

技术标签:

【中文标题】Python 使用省略号或无 + 浮点类型提示未分配属性【英文标题】:Python leaving attribute unassigned with ellipsis or None + type hint of float 【发布时间】:2020-04-03 02:53:16 【问题描述】:

问题

我想声明一个实例属性,类型提示为float,而不在初始化时分配值。该值在运行时分配,在实例初始化之后(也就是在__init__ 之后)。

根据this answer,我可以将值设置为None。但是,我的 IDE (PyCharm) 提出了一个 PyTypeChecker 标志,表示 Expected type 'float', got type 'None' instead

我发现如果我将值设置为省略号(this answer 建议),又名 value = ...,PyCharm 不再抱怨。

这里的最佳做法是什么?我应该使用None 还是...


示例代码

class SomeClass:

    def __init__(self):
        """Initialize with an unassigned value."""

        # PyCharm complains here
        self._unassigned_val = None  # type: float

        # PyCharm doesn't complain here
        self._unassigned_val2 = ...  # type: float

    def called_during_runtime(self) -> None:
        """This gets called after __init__ has run."""
        self._unassigned_val = 1.0
        self._unassigned_val2 = 1.0

在我的 IDE 中的样子:


版本信息

PyCharm 社区版2019.2.5 蟒蛇3.6

【问题讨论】:

called_during_runtime 何时真正被调用? @user1558604 我刚刚更新了问题,它在对象初始化后几分钟被调用到运行时 我认为None 将是官方答案,因为省略号没有官方用途。我怀疑您是否甚至需要将这些属性设置为__init__ 中的任何内容。如果我的代码在设置之前意外要求该属性,我认为我个人更愿意获得AttributeError,而不是获得一个随机值(None...),然后我必须弄清楚如何处理。 如果您将变量注释为Optional[float],PyCharm 会停止抱怨吗? (你需要导入它,from typing import Optional @user1558604 我认为这是一种更好的方法,也感谢您的建议! 【参考方案1】:

对于简单的情况,您实际上可以在构造函数中不做任何事情:如果您这样做,mypy 和 Pycharm 将继续正确推断您的字段的类型:

class SomeClass:
    def called_during_runtime(self) -> None:
        self._unassigned_val = 1.0

当然,您需要承担确保在运行时实际调用此函数的责任:如果您这样做,您的类型检查器不会警告您。

如果您的函数以足够复杂的方式为该字段分配值,您的类型检查器可能会卡住并且不知道该怎么做。在这种情况下,如果您使用的是 Python 3.6 或更高版本,则可以使用 Variable annotations:

class SomeClass:
    _unassigned_val: float

    def called_during_runtime(self) -> None:
        self._unassigned_val = 1.0

这与运行时的第一种方法完全相同。

如果您需要支持旧版本的 Python,您可以做的另一种技术是创建一个“虚假”标记值,该值的类型为 Any,即完全动态类型:

from typing import Any

BOGUS = object()  # type: Any

class SomeClass:
    def __init__(self) -> None:
        self._unassigned_val = BOGUS  # type: float

    def called_during_runtime(self) -> None:
        self._unassigned_val = 1.0

如果您改变主意并决定更倾向于类型检查器并对其警告进行更积极的处理,您始终可以声明您的值可以是 浮动或无:

from typing import Optional

class SomeClass:
    def __init__(self) -> None:
        self._unassigned_val = None  # type: Optional[float]

    def called_during_runtime(self) -> None:
        self._unassigned_val = 1.0

    def get_with_default(self, default: float) -> float:
        if self._unassigned_val is None:
            return default
        else:
            return self._unassigned_val

请注意,然后您可以在 if 语句和断言中使用 self._unassigned_val is not Noneself._unassigned_val is Noneisinstance(self._unassigned_val, float) 检查的组合,以使您的类型检查器有条件地缩小字段的类型。

这最后一种方法是我个人所做的:我是类型检查器的粉丝,我将我的工具设置为非常积极地检测潜在问题。

关于省略号的最后一点注意事项:使用省略号作为占位符仅适用于存根以及使用 Protocols 方法定义或 abstract classes 之类的东西时——基本上,在您从未最终实际使用的值的情况下您的字段/方法参数/运行时的任何内容。

【讨论】:

以上是关于Python 使用省略号或无 + 浮点类型提示未分配属性的主要内容,如果未能解决你的问题,请参考以下文章

C语言中有32个关键词,9种控制语句,34种运算符,分别是哪些?

python正则

python基础及函数1

评估 numpy.radians 和浮点/数组输入元素的类型提示

网络连接提示受限制或无连接怎么回事?

iOS无网络提示或无数据提示