zat*_*heo 10 python type-hinting mypy python-typing python-3.9
目前,当我无法在函数签名中分配默认参数和/或已经具有含义时,我会使用此策略。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).')
Run Code Online (Sandbox Code Playgroud)
错误:
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)
Run Code Online (Sandbox Code Playgroud)
ham而不出现错误?或者DEFAULT = object()?Blc*_*ght 12
正如我所评论的,这是 Python 的一个活跃的开发领域。PEP 661建议添加一个sentinel创建哨兵对象的函数,但在该 PEP 获得批准之前,您只能靠自己了。
不过,您可以从 PEP 中提出的(或拒绝的)一些选项中获得灵感。一种非常简单的方法,可以很好地使用类型提示,那就是让你的哨兵值成为一个类:
class DEFAULT: pass
Run Code Online (Sandbox Code Playgroud)
现在,您可以将函数类型提示为采用类型的联合,其中包括type[DEFAULT]:
def spam(ham: list[str]|None|type[DEFAULT] = DEFAULT):
Run Code Online (Sandbox Code Playgroud)
我喜欢做的事情 \xe2\x80\x94 这只是@Blckknght\'s 答案\xe2\x80\x94 的一个微小变化,那就是使用元类给我的哨兵类一个更好的表示并使其始终错误。
\n哨兵.py
\nfrom typing import Literal \n\nclass SentinelMeta(type):\n def __repr__(cls) -> str:\n return f\'<{cls.__name__}>\'\n\n def __bool__(cls) -> Literal[False]:\n return False\n\n\nclass Sentinel(metaclass=SentinelMeta): pass\nRun Code Online (Sandbox Code Playgroud)\n主要.py
\nfrom sentinel import Sentinel\n\nclass DEFAULT(Sentinel): pass\nRun Code Online (Sandbox Code Playgroud)\n您在类型提示中使用它的方式与 @Blckknght 建议的方式完全相同:
\ndef spam(ham: list[str]|None|type[DEFAULT] = DEFAULT): ...\nRun Code Online (Sandbox Code Playgroud)\n但你还有一个额外的优势,那就是你的哨兵值总是错误的,并且有更好的表现:
\n>>> DEFAULT\n<DEFAULT>\n>>> bool(DEFAULT)\nFalse\nRun Code Online (Sandbox Code Playgroud)\n