Bra*_*mon 5 python python-3.x mypy python-typing
考虑typing.TypeVar直接来自打字文档的以下插图:
# mypytest.py
from typing import TypeVar
A = TypeVar("A", str, bytes) # I.e. typing.AnyStr
def longest(x: A, y: A) -> A:
"""Return the longest of two strings."""
# https://docs.python.org/3/library/typing.html
return x if len(x) >= len(y) else y
Run Code Online (Sandbox Code Playgroud)
调用mypy mypytest.py不会引发错误并退出 0。本示例中的目的是A可以是str或bytes,但返回类型将与传递的类型一致。
但是,当存在默认参数时,mypy 将引发错误:
def longest_v2(x: A = "foo", y: A = "bar") -> A:
return x if len(x) >= len(y) else y
Run Code Online (Sandbox Code Playgroud)
提高:
$ mypy mypytest.py
mypytest.py:11: error: Incompatible default for argument "x" (default has type "str", argument has type "bytes")
mypytest.py:11: error: Incompatible default for argument "y" (default has type "str", argument has type "bytes")
Run Code Online (Sandbox Code Playgroud)
为什么在第二种情况下会发生错误?
使用行号:
1 # mypytest.py
2 from typing import TypeVar
3
4 A = TypeVar("A", str, bytes) # I.e. typing.AnyStr
5
6 def longest(x: A, y: A) -> A:
7 """Return the longest of two strings."""
8 # https://docs.python.org/3/library/typing.html
9 return x if len(x) >= len(y) else y
10
11 def longest_v2(x: A = "foo", y: A = "bar") -> A:
12 return x if len(x) >= len(y) else y
Run Code Online (Sandbox Code Playgroud)
我知道这个问题很老了,但它似乎引起了足够的关注。
您描述的问题是一个众所周知的问题。这是跟踪问题。
对于函数来说,这只是一个mypy限制(这就是问题仍然悬而未决的原因)。为了使事情正常运行而不忽略注释,您可以引入两个重载:
from typing import TypeVar, overload
_T = TypeVar("_T", str, bytes) # I.e. typing.AnyStr
@overload
def longest_v2(x: str = ...) -> str: ...
@overload
def longest_v2(x: _T, y: _T) -> _T: ...
def longest_v2(x: str | bytes = 'foo', y: str | bytes = 'bar') -> str | bytes:
return x if len(x) >= len(y) else y
reveal_type(longest_v2()) # N: revealed type is "builtins.str"
reveal_type(longest_v2('foo')) # N: revealed type is "builtins.str"
longest_v2(b'foo') # E: No overload variant of "longest_v2" matches argument type "bytes" [call-overload]
reveal_type(longest_v2('foo', 'bar')) # N: revealed type is "builtins.str"
reveal_type(longest_v2(b'foo', b'bar')) # N: revealed type is "builtins.bytes"
Run Code Online (Sandbox Code Playgroud)
实现签名并不重要,因为它对外部调用者不可见。第一个重载对应于带有 0 或 1 个参数的调用:第二个参数有一个默认字符串,因此应该在未给出时_T解析,这就是我们所做的。str第二个重载涵盖了提供两个参数的情况。
我认为,该功能尚未实现的原因与类中的重载有关,尤其是与类中的重载有关。在类“构造函数”__new__和中__init__,类似的行为是不安全的。问题中的示例:
from collections import OrderedDict
from typing import Generic, Mapping, TypeVar
_T1 = TypeVar('_T1', bound=Mapping)
class RawConfigParser(Generic[_T1]):
def __init__(self, dict_type: type[_T1] = OrderedDict) -> None: ...
def defaults(self) -> _T1: ...
class UserMapping(Mapping):
...
RawConfigParser[UserMapping]() # Oops!
Run Code Online (Sandbox Code Playgroud)
这也可以修复(通过将此类调用标记为无效),但这需要在mypy实现中进行更多更改。
| 归档时间: |
|
| 查看次数: |
482 次 |
| 最近记录: |