如何解决Python类型提示:Callable后跟TypeVar是什么意思? 简化示例原始源代码
我正在尝试理解以下代码中的类型提示Getter[T]
:
简化示例
T = TypeVar('T')
Getter = Callable[[T,str],str]
class AbstractClass(abc.ABC):
@abc.abstractmethod
def extract(
self,get_from_carrier: Getter[T],# <---- See here
...
) -> Context:
自从我为此奋斗以来,对此深表感谢。
原始源代码
原始源代码来自OpenTelemetry project file "textmap.py":
import abc
import typing
from opentelemetry.context.context import Context
TextMapPropagatorT = typing.TypeVar("TextMapPropagatorT")
Setter = typing.Callable[[TextMapPropagatorT,str,None]
Getter = typing.Callable[[TextMapPropagatorT,typing.List[str]]
class TextMapPropagator(abc.ABC):
"""This class provides an interface that enables extracting and injecting
context into headers of HTTP requests.
...
"""
@abc.abstractmethod
def extract(
self,get_from_carrier: Getter[TextMapPropagatorT],carrier: TextMapPropagatorT,context: typing.Optional[Context] = None,) -> Context:
解决方法
后跟类型变量的Callable表示该callable是一个通用函数,它接受一个或多个通用类型T
的参数。
类型变量T
是任何通用类型的参数。
该行:
Getter = Callable[[T,str],str]
将Getter
定义为可调用函数的类型别名,该可调用函数的参数为通用类型T
和string,返回类型为string。
因此,该行:
get_from_carrier: Getter[T]
定义作为通用函数的参数(get_from_carrier
)。泛型函数的第一个参数是泛型类型T
。
具体示例
通过查看一个具体示例可以更好地理解这一点。请参见以下"instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/init.py "中的propagators.extract
:
在调用propagators.extract
中,函数get_header_from_scope
是可调用函数,其第一个参数的类型为dict
,并且此dict
用作{{1} }。
TextMapPropagatorT
,
tl; dr: _C[_T]
是一个通用类型别名,等效于Callable[[_T,int],int]
。
在这里,您将_C
定义为Callable[[_T,int]
的类型别名。当类型别名包含TypeVar
(在这种情况下为_T
)时,它将成为generic type alias。您可以像使用List[T]
或Dict[K,V]
这样的内置泛型类型一样使用它,例如,_C[str]
等同于Callable[[str,int]
。>
然后,get_from_elem
的类型注释将其定义为generic function。这意味着在整个函数中使用的同一类型变量应绑定到同一类。要解释这意味着什么,请看一下这些函数调用:
_T = typing.TypeVar('_T')
_C = typing.Callable[[_T,int]
def get_from_elem(get: _C[_T],elem: _T):
...
def foo_str(a: str,b: int) -> int:
# This function matches `_C[str]`,i.e. `Callable[[str,int]`
...
def foo_float(a: float,b: int) -> int:
# This function matches `_C[float]`,i.e. `Callable[[float,int]`
...
def foo_generic(a: _T,b: int) -> int:
# This function matches `_C[_T]`,it is also a generic function
...
_T2 = typing.TypeVar('_T2',str,bytes)
def foo_str_like(a: _T2,b: int) -> int:
# A generic function with constraints: type of first argument must be `str` or `bytes`
...
get_from_elem(foo_str,"abc") # Correct: `_T` is bound to `str`
get_from_elem(foo_float,1.23) # Correct: `_T` is bound to `float`
get_from_elem(foo_str,1.23) # Wrong: `_T` bound to two different types `str` and `float`
get_from_elem(foo_float,[1.23]) # Wrong: `_T` bound to two different types `float` and `List[float]`
get_from_elem(foo_generic,1.45) # Correct: `_T` is only bound to `float`
get_from_elem(foo_str_like,1.45) # Wrong: `_T` is only bound to `float`,but doesn't satisfy `foo_str_like` constraints
在后两种情况下,第一个参数是泛型函数,它不绑定类型变量,因此类型变量仅由第二个参数绑定。但是,在最后一种情况下,foo_str_like
对其第一个参数类型具有附加约束,并且绑定类型float
不满足该约束,因此它无法进行类型检查。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。