问题
我想声明一个实例属性,类型提示为float
,而不在初始化时分配值。该值是在实例初始化后(也称为__init__
之后)在运行时分配的。
根据this answer,我可以将值设置为None
。但是,我的IDE(PyCharm
)引发一个PyTypeChecker
标志,说Expected type 'float', got type 'None' instead
。
[我发现是否将值设置为省略号(由this answer表示),又名值= ...
,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中看起来像:
版本信息
2019.2.5
3.6
对于简单的情况,您实际上可以不用在构造函数中执行任何操作:如果执行此操作,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
而且,如果您改变主意并决定要偏向于类型检查器以使其警告更为激进,则始终可以声明您的值可以为任一个] float或None:
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 None
或isinstance(self._unassigned_val, float)
的组合,以使类型检查器有条件地缩小字段的类型。
这是我个人的最后一种方法:我是类型检查器的狂热者,并且设置我的工具以非常主动地检测潜在的问题。
关于省略号的最后注解:仅在存根以及使用Protocols方法定义或abstract classes之类的东西时,才将省略号用作占位符-基本上,在您最终没有真正使用自己的值的情况下字段/方法参数/无论何时运行。