gpt4 book ai didi

Python 输入 : Concatenate sequences

转载 作者:行者123 更新时间:2023-12-03 20:02:23 25 4
gpt4 key购买 nike

在 python 中,两个序列的连接通常由 + 完成。运算符(operator)。但是,mypy 提示以下内容:

from typing import Sequence

def concat1(a: Sequence, b: Sequence) -> Sequence:
return a + b
没错: Sequence没有 __add__ .但是,该函数对于“通常”的序列类型非常有效 list , str , tuple .显然,还有其他序列类型不起作用(例如 numpy.ndarray )。一个解决方案可能是:
from itertools import chain

def concat2(a: Sequence, b: Sequence) -> Sequence:
return list(chain(a, b))
现在,mypy 没有提示。但是连接字符串或元组总是给出一个列表。似乎有一个简单的解决方法:
def concat3(a: Sequence, b: Sequence) -> Sequence:
T = type(a)
return T(chain(a, b))
但是现在 mypy 很不高兴,因为 T get 的构造函数的参数太多了。更糟糕的是,该函数不再返回一个序列,而是返回一个生成器。
这样做的正确方法是什么?
我觉得问题的一部分是 a 和 b 应该具有相同的类型,并且输出也将是相同的类型,但是类型注释没有传达它。
注意:我知道使用 ''.join(a, b) 连接字符串更有效。 .然而,我选择这个例子更多是为了说明。

最佳答案

没有通用的方法来解决这个问题:Sequence包括不能以通用方式连接的类型。例如,无法连接任意 range对象创建一个新的range并保留所有元素。
必须决定一种具体的连接方式,并将可接受的类型限制为提供所需操作的类型。
最简单的方法是让函数只请求所需的操作。万一pre-built protocols in typing 还不够,可以回退定义自定义 typing.Protocol对于请求的操作。

由于concat1/concat_add需要 +实现,一个 Protocol__add__是需要的。此外,由于加法通常适用于相似的类型,__add__必须在具体类型上进行参数化——否则,协议(protocol)要求所有可添加类型,这些可添加类型可以添加到所有其他可添加类型。

# TypeVar to parameterize for specific types
SA = TypeVar('SA', bound='SupportsAdd')


class SupportsAdd(Protocol):
"""Any type T where +(:T, :T) -> T"""
def __add__(self: SA, other: SA) -> SA: ...


def concat_add(a: SA, b: SA) -> SA:
return a + b
这足以安全地连接基本序列,并拒绝混合类型连接。
reveal_type(concat_add([1, 2, 3], [12, 17])) # note: Revealed type is 'builtins.list*[builtins.int]'
reveal_type(concat_add("abc", "xyz")) # note: Revealed type is 'builtins.str*'
reveal_type(concat_add([1, 2, 3], "xyz")) # error: ...
请注意,这允许连接任何实现 __add__ 的类型。 ,例如 int .如果需要进一步的限制,请更严格地定义协议(protocol)——例如通过要求 __len____getitem__ .

通过链接键入连接有点复杂,但遵循相同的方法:A Protocol定义了函数所需的能力,但为了类型安全,元素也应该被类型化。
# TypeVar to parameterize for specific types and element types
C = TypeVar('C', bound='Chainable')
T = TypeVar('T', covariant=True)


# Parameterized by the element type T
class Chainable(Protocol[T]):
"""Any type C[T] where C[T](:Iterable[T]) -> C[T] and iter(:C[T]) -> Iterable[T]"""
def __init__(self, items: Iterable[T]): ...

def __iter__(self) -> Iterator[T]: ...


def concat_chain(a: C, b: C) -> C:
T = type(a)
return T(chain(a, b))
这足以安全地连接由它们自身构造的序列,并拒绝混合类型的连接和非序列。
reveal_type(concat_chain([1, 2, 3], [12, 17])) # note: Revealed type is 'builtins.list*[builtins.int]'
reveal_type(concat_chain("abc", "xyz")) # note: Revealed type is 'builtins.str*'
reveal_type(concat_chain([1, 2, 3], "xyz")) # error: ...
reveal_type(concat_chain(1, 2)) # error: ...

关于Python 输入 : Concatenate sequences,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65361188/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com