以标记值作为默认值的类型提示参数
Type-hinting parameters with a sentinel value as the default
当我无法在函数签名中分配默认参数时,我目前使用 this strategy and/or None
已经有意义了。
from typing import Optional
DEFAULT = object()
# `None` already has meaning.
def spam(ham: Optional[list[str]] = DEFAULT):
if ham is DEFAULT:
ham = ['prosciutto', 'jamon']
if ham is None:
print('Eggs?')
else:
print(str(len(ham)) + ' ham(s).')
错误:
Failed (exit code: 1) (2607 ms)
main.py:7: error: Incompatible default for argument "ham" (default has type "object", argument has type "Optional[List[str]]")
Found 1 error in 1 file (checked 1 source file)
- 如何输入提示
ham
而不会在 mypy 中出现错误? 或
- 我应该使用什么策略而不是
DEFAULT = object()
?
正如我评论的那样,这是 Python 中一个活跃的开发领域。 PEP 661 建议添加一个 sentinel
函数来创建哨兵对象,但在该 PEP 获得批准之前,您只能靠自己了。
不过,您可以从 PEP 中的一些提议(或拒绝)选项中获得灵感。一种与类型提示配合得相当好的非常简单的方法是让你的标记值成为 class:
class DEFAULT: pass
现在您可以对函数进行类型提示,将其作为包含 type[DEFAULT]
:
的类型联合
def spam(ham: list[str]|None|type[DEFAULT] = DEFAULT):
我喜欢做的事情——这只是 的一个细微变化——是使用 metaclass 给我的 sentinel class 一个更好的 repr 并让它始终-假。
sentinel.py
from typing import Literal
class SentinelMeta(type):
def __repr__(cls) -> str:
return f'<{cls.__name__}>'
def __bool__(cls) -> Literal[False]:
return False
class Sentinel(metaclass=SentinelMeta): pass
main.py
from sentinel import Sentinel
class DEFAULT(Sentinel): pass
您在类型提示中使用它的方式与@Blckknght 建议的完全相同:
def spam(ham: list[str]|None|type[DEFAULT] = DEFAULT): ...
但是你有额外的优势,你的哨兵值总是假的并且有更好的表现:
>>> DEFAULT
<DEFAULT>
>>> bool(DEFAULT)
False
当我无法在函数签名中分配默认参数时,我目前使用 this strategy and/or None
已经有意义了。
from typing import Optional
DEFAULT = object()
# `None` already has meaning.
def spam(ham: Optional[list[str]] = DEFAULT):
if ham is DEFAULT:
ham = ['prosciutto', 'jamon']
if ham is None:
print('Eggs?')
else:
print(str(len(ham)) + ' ham(s).')
错误:
Failed (exit code: 1) (2607 ms)
main.py:7: error: Incompatible default for argument "ham" (default has type "object", argument has type "Optional[List[str]]")
Found 1 error in 1 file (checked 1 source file)
- 如何输入提示
ham
而不会在 mypy 中出现错误? 或 - 我应该使用什么策略而不是
DEFAULT = object()
?
正如我评论的那样,这是 Python 中一个活跃的开发领域。 PEP 661 建议添加一个 sentinel
函数来创建哨兵对象,但在该 PEP 获得批准之前,您只能靠自己了。
不过,您可以从 PEP 中的一些提议(或拒绝)选项中获得灵感。一种与类型提示配合得相当好的非常简单的方法是让你的标记值成为 class:
class DEFAULT: pass
现在您可以对函数进行类型提示,将其作为包含 type[DEFAULT]
:
def spam(ham: list[str]|None|type[DEFAULT] = DEFAULT):
我喜欢做的事情——这只是
sentinel.py
from typing import Literal
class SentinelMeta(type):
def __repr__(cls) -> str:
return f'<{cls.__name__}>'
def __bool__(cls) -> Literal[False]:
return False
class Sentinel(metaclass=SentinelMeta): pass
main.py
from sentinel import Sentinel
class DEFAULT(Sentinel): pass
您在类型提示中使用它的方式与@Blckknght 建议的完全相同:
def spam(ham: list[str]|None|type[DEFAULT] = DEFAULT): ...
但是你有额外的优势,你的哨兵值总是假的并且有更好的表现:
>>> DEFAULT
<DEFAULT>
>>> bool(DEFAULT)
False