Protocol.__call__ 与 Callable 之间的区别?

问题描述 投票:0回答:1

我有一个功能

def run_thing(cb: Callback) -> Result:
  w: Widget = make_widget()
  res: Result = cb(w)
  return res

我可以想象两种方法来定义回调类型。

# Option 1: Callable
# https://docs.python.org/3/library/typing.html#annotating-callables
Callback = typing.Callable[[Widget],Result]
# Option 2: Protocol
# https://docs.python.org/3/library/typing.html#typing.Protocol
class Callback(typing.Protocol):
  def __call__(self,w: Widget) -> Result:
    ...

在决定上述两种类型定义时需要考虑哪些细微差别?

python typing callable
1个回答
0
投票

Callable
可以用于简单的情况,但对于复杂的签名来说就太有限了。

文档对此进行了解释,该文档还建议使用以下引用和示例片段定义

Protocol
作为替代方案:

Callable 无法表达复杂的签名,例如采用可变数量参数的函数、重载函数或仅具有关键字参数的函数。然而,这些签名可以通过定义一个带有

Protocol
方法的
__call__()
类来表达:

--- Python 的

typing
文档

from collections.abc import Iterable
from typing import Protocol

class Combiner(Protocol):
    def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ...

def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes:
    for item in data:
        ...

def good_cb(*vals: bytes, maxlen: int | None = None) -> list[bytes]:
    ...
def bad_cb(*vals: bytes, maxitems: int | None) -> list[bytes]:
    ...

batch_proc([], good_cb)  # OK
batch_proc([], bad_cb)   # Error! Argument 2 has incompatible type because of
                         # different name and kind in the callback
© www.soinside.com 2019 - 2024. All rights reserved.