当python类型需要子类的父类时,如何让它将子类识别为有效类型?

2024-07-02 12:42:17 发布

您现在位置:Python中文网/ 问答频道 /正文

以下是我需要做的一个简单示例:

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分别是数据和事件的子类型,所以一切都应该正常。有没有办法让这项工作如我所料?我的想法是这样做:

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函数尽可能通用。现在,这给出了与上面相同的警告


Tags: runinfoeventdatadefanypassclass
2条回答

参数子类型与返回子类型的方向相反

  • 返回值从被调用方分配给调用方
  • 参数值从调用者分配给被调用者

赋值应该比变量的预期类型更具体。 例如:

data: Data = SpecificData()  # okay
data: SpecificData = Data()  # not okay

所以你应该:

from typing import Callable, Any


class Data:
    pass


class SpecificData(Data):
    pass


class Event:
    pass


class SpecificEvent(Event):
    pass


def detect_specific_event(data: Data, other_info: str) -> SpecificEvent:
    return SpecificEvent()


def run_detection(callback: Callable[[SpecificData, Any], Event]) -> None:
    return


run_detection(detect_specific_event)

我花了一段时间才记住要使用哪种类型,但我想知道您想使用哪种类型的cast

与它在其他语言中的使用不同,cast(x,y)不做任何事,但它告诉键入将y视为类型x。运行时,它是一个no-op,只返回y

就像编译语言一样,如果我阅读它,我会特别注意代码:这真的在运行时起作用吗?数据类型是否正确?

  • 如果不能保证以后生成数据的内容只会发出SpecificData,那么使用LSP注释的重复闭包是合适的。如果可以的话,铸造就可以了。您的最小示例缺少该位,但是如果您已经显示了实际数据通过print(data),那么我们就知道是否应用了LSP
from typing import Callable, Any, cast


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(cast((Callable[[Data, Any], Event]),detect_specific_event))

在这里,你基本上告诉打字,“接受我的话”,即detect_specific_event是一个Callable[[Data, Any], Event])

运行和类型检查的输出:

$ mypy test2.py
Success: no issues found in 1 source file
$ python test2.py
(venv)$  😃 well your code says nothing.

将cast更改为实际sig:

run_detection(cast((Callable[[SpecificData, Any], SpecificEvent]),detect_specific_event))

(venv) $@so.mypy$ mypy test2.py
Argument 1 to "run_detection" has incompatible type "Callable[[SpecificData, Any], SpecificEvent]"; expected "Callable[[Data, Any], Event]"
Found 1 error in 1 file (checked 1 source file)
$ python test2.py 
$😃 well your code says nothing.

相关问题 更多 >