以 json
module docs 中的示例为例:
>>> def as_complex(dct):
... if '__complex__' in dct:
... return complex(dct['real'], dct['imag'])
... return dct
在这里添加类型提示的正确方法是什么?我使用 TypedDict
和重载的天真方法失败了:
from typing import Any, Dict, TypedDict, TypeVar, Union, overload
_T = TypeVar('_T', bound=Dict[str, Any])
class JSONDict(TypedDict):
__complex__: Any
real: float
imag: float
@overload
def as_complex(dct: JSONDict) -> complex: ...
@overload
def as_complex(dct: _T) -> _T: ...
def as_complex(dct: _T) -> Union[complex, _T]:
if '__complex__' in dct:
return complex(dct['real'], dct['imag'])
return dct
作为 mypy
对象:
main.py:14: error: Overloaded function signatures 1 and 2 overlap with incompatible return types
main.py:19: error: Overloaded function implementation cannot satisfy signature 1 due to inconsistencies in how they use type variables
Playground gist , 如果您想在浏览器中试用示例。
最佳答案
显然 mypy
将 JSONDict
和 _T
视为重叠类型,很可能是由于 Any
在 TypeVar
定义。
这让我想起了以下情况(只是示例):
class A: ...
class B: ...
class C: ...
class D: ...
@overload
def f(x: Union[A, B]) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
@overload
def f(x: Union[B, C]) -> str: ...
def f(x): ...
我们可以让它们重叠或尝试将它们分开。目前,我可以提出两个相当丑陋的解决方案。
from typing import Any, Dict, TypedDict, TypeVar, Union, overload, cast
_T = TypeVar('_T', bound=Dict[str, Any])
class JSONDict(TypedDict):
__complex__: Any
real: float
imag: float
@overload
def as_complex(dct: JSONDict) -> complex: ...
@overload
def as_complex(dct: _T) -> Union[_T, complex]: ...
def as_complex(dct: Union[_T, JSONDict]) -> Union[complex, _T]:
if '__complex__' in dct:
return complex(dct['real'], dct['imag'])
return cast(_T, dct)
或者尝试分开
from typing import Any, Dict, TypedDict, TypeVar, Union, overload, cast
# narrowing the list of types excluding float
_T = TypeVar('_T', bound=Dict[str, Union[int, str, list, tuple, dict, set]])
class JSONDict(TypedDict):
__complex__: Any
real: float
imag: float
@overload
def as_complex(dct: JSONDict) -> complex: ...
@overload
def as_complex(dct: _T) -> _T: ...
def as_complex(dct: Union[_T, JSONDict]) -> Union[complex, _T]:
if '__complex__' in dct:
dct = cast(JSONDict, dct)
return complex(dct['real'], dct['imag'])
return cast(_T, dct)
希望有人能提出更优雅的解决方案
关于python - 向 JSON 对象 Hook 添加类型提示的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63331368/