这是我需要做的一个最小示例:
from typing import Callable, Any
class Data:
pass
class SpecificData(Data):
pass
class Event:
pass
class SpecificEvent(Event):
pass
def detect_specific_event(data: SpecificData, other_info: str) -> SpecificEvent:
return SpecificEvent()
def run_detection(callback: Callable[[Data, Any], Event]) -> None:
return
run_detection(detect_specific_event)
现在我收到警告:
Expected type '(Data, Any) -> Event', got '(data: SpecificData, other_info: str) -> SpecificEvent' instead
对我来说,这个警告似乎没有意义,因为 SpecificData 和 SpecificEvent 分别是 Data 和 Event 的子类型,所以一切都应该很好。有没有办法让这个工作如我所期望的那样?我的想法是能够有类似的东西:
class OtherSpecificData(Data):
pass
class OtherSpecificEvent(Event):
pass
def detect_other_event(data: OtherSpecificData, other_info: str) -> OtherSpecificEvent:
return OtherSpecificEvent()
run_detection(detect_other_event)
所以
run_detection
功能尽可能通用。现在这给出了与上面相同的警告。
你遇到的问题是类型提示中的
协变
和
逆变
。在你的例子中,你想将一个接受
SpecificData
(
Data
的子类)并返回
SpecificEvent
(
Event
的子类)的函数传递给一个期望接受
Data
并返回
Event
的函数的函数。
-
协变:
函数的返回类型可以是更具体的类型,但不能是更通用的类型。例如,返回
SpecificEvent
可以接受为返回Event
,但反之则不行。 -
逆变:
函数的参数类型可以是更通用的类型,但不能是更具体的类型。例如,接受
Data
可以接受为接受SpecificData
,但反之则不行。
你的代码中出现类型错误的原因是,
Callable[[Data, Any], Event]
期望一个可以处理
任何
Data
子类型的函数,而你提供的函数只能处理
SpecificData
。
你可以使用 类型变量 和 类型约束 来解决这个问题,使其更加通用:
from typing import Callable, Any, TypeVar, Generic
TData = TypeVar('TData', bound=Data)
TEvent = TypeVar('TEvent', bound=Event)
class Data:
pass
class SpecificData(Data):
pass
class Event:
pass
class SpecificEvent(Event):
pass
def detect_specific_event(data: SpecificData, other_info: str) -> SpecificEvent:
return SpecificEvent()
def run_detection(callback: Callable[[TData, Any], TEvent], data: TData, other_info: Any) -> TEvent:
return callback(data, other_info)
run_detection(detect_specific_event, SpecificData(), "")
在这个改进的版本中,我们引入了两个类型变量
TData
和
TEvent
,它们分别受限于
Data
和
Event
。这允许
run_detection
函数接受任何接受
Data
子类型并返回
Event
子类型的函数。
现在,你可以定义其他数据和事件类型,并使用相同的
run_detection
函数:
class OtherSpecificData(Data):
pass
class OtherSpecificEvent(Event):
pass
def detect_other_event(data: OtherSpecificData, other_info: str) -> OtherSpecificEvent:
return OtherSpecificEvent()
run_detection(detect_other_event, OtherSpecificData(), "")
标签:python,python-typing
From: 60447851