Python 使用省略号或 None + float 类型提示未分配属性
Python leaving attribute unassigned with ellipsis or None + type hint of float
问题
我想声明一个实例属性,类型提示为 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 中的样子:
版本信息
- PyCharm 社区版
2019.2.5
- Python
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,您可以使用的另一种技术是创建一个 "bogus" 标记值,该值的类型为 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 method definitions or abstract classes 之类的东西时 - 基本上,在您永远不会实际使用您的值的情况下 field/method parameters/whatever 在运行时。
问题
我想声明一个实例属性,类型提示为 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 中的样子:
版本信息
- PyCharm 社区版
2019.2.5
- Python
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,您可以使用的另一种技术是创建一个 "bogus" 标记值,该值的类型为 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 method definitions or abstract classes 之类的东西时 - 基本上,在您永远不会实际使用您的值的情况下 field/method parameters/whatever 在运行时。