首页 > 解决方案 > Python 使用省略号或无 + 浮点类型提示未分配属性

问题描述

问题

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

根据这个答案,我可以将值设置为None。但是,我的 IDE ( PyCharm) 提出了一个PyTypeChecker标志,说Expected type 'float', got type 'None' instead.

我发现如果我将值设置为省略号(由这个答案建议),也就是 value = ...,PyCharm 不再抱怨。

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


示例代码

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 中的示例代码


版本信息

标签: pythonpycharmtype-hintingellipsisduck-typing

解决方案


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

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

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

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

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 None,以使您的类型检查器有条件地缩小字段的类型。self._unassigned_val is Noneisinstance(self._unassigned_val, float)

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

关于省略号的最后一点注意事项:使用省略号作为占位符仅适用于存根以及使用诸如协议方法定义或抽象类之类的东西时- 基本上,在您从未最终实际使用字段/方法参数的值的情况下/无论在运行时。


推荐阅读