我有一个带有输入参数的Python函数,其值控制返回值的类型。该参数可以省略(默认值None
),在这种情况下使用模块级变量。这样,可以通过更改模块级别变量来更改默认行为。一个最小的例子:
from typing import overload, Union, Literal, Optional
option_default: Literal["str", "int"] = "int"
@overload
def test(option: Literal["str"]) -> str:
...
@overload
def test(option: Literal["int"]) -> int:
...
@overload
def test(option: Literal[None] = None) -> Union[str, int]:
...
def test(option: Optional[Literal["str", "int"]] = None) -> Union[str, int]:
if option is None:
option = option_default
if option == "str":
return "foo"
else:
return 1
foo: int = test() # Incompatible types in assignment (expression has type "Union[str, int]", variable has type "int")
option_default = "str"
baz: str = test() # Incompatible types in assignment (expression has type "Union[str, int]", variable has type "str")
通常人们会使用typing.overload
来处理这种情况。然而,对于没有参数的test()
,这不起作用-因此我的错误。这里是否有更好的方式来提供类型信息?
那不可能。GitHub上有一个建议,从TypeScript中添加typeof
,但这是另一回事-它不会像你所展示的那样跟踪可变变量。
我不认为这样的功能可以实现,即使在理论上。它给类型检查带来了许多新的复杂性。我可以想到一些有问题的场景:
- 传递回调
def foo(callback: Callable[[], int]):
some_module.definitely_returns_an_int = callback
option_default = "int"
foo(test) # ok?
option_default = "str"
现在foo
已经保存了一个返回字符串的函数。
- 跟踪函数内部发生的突变
def ints_are_the_bomb():
global option_default
option_default = "int"
option_default = "str"
some_other_module.baz()
value = test()
你能确定value
的类型吗?不能保证some_other_module.baz()
没有调用your_module.ints_are_the_bomb()
。所以现在您需要跟踪可能发生在your_module.option_default
上的所有更改,可能是跨模块的更改。如果客户端代码(如果这是一个库)可以改变标志,那么这是不可能的。
概括地说,当你改变某些东西时,值(包括函数)的类型不能改变。这可能会破坏远程代码,而这些代码恰好也引用了这个对象。