拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 实作协议的Python泛型型别

实作协议的Python泛型型别

白鹭 - 2022-02-14 1963 0 0

物件 A、B ... 具有属性namespace,我有一个函式,可以通过一组特定的namespace属性值过滤此类物件的串列

T = TypeVar('T')


def filter(seq: list[T], namespace_values: set[str]) -> list[T]:
    # Returns a smaller list containing only the items from
    # `seq` whose `namespace` are in `namespace_values`
    ...

这很有效,但它允许传递没有任何检查错误X的属性型别的物件namespace

然后我创建了一个协议并更改了函式以使用该协议:


class Namespaced(Protocol):
    namespace: str

def filter(seq: list[Namespaced], namespace_values: set[str]) -> list[Namespaced]:
    # Returns a smaller list containing only the items from
    # `seq` whose `namespace` are in `namespace_values`
    ...

现在,如果我通过一个串列X(这是我想要的),我会收到一个检查错误,但是我丢失了泛型:


list_of_a: list[A] = [a1, a2, a3]

output = filter(list_of_a, ['ns1', 'ns2'])

# output is list[Namespaced] instead of list[A]

如何组合泛型和协议,以便我的函式回传 T 型别的串列,并检查seq的项目是否实作了Namespaced协议?

我尝试了以下方法,但T丢失了。


def filter(seq: list[Namespaced[T]], namespace_values: set[str]) -> list[T]:
    # Returns a smaller list containing only the items from
    # `seq` whose `namespace` are in `namespace_values`
    ...

干杯!

uj5u.com热心网友回复:

使用系结型别变量和协议作为系结。考虑以下模块:

(py39) Juans-MacBook-Pro:~ juan$ cat test.py

其中有:

from typing import TypeVar, Protocol
from dataclasses import dataclass

class Namespaced(Protocol):
    namespace: str


T = TypeVar("T", bound="Namespaced")

@dataclass
class Foo:
    namespace: str

@dataclass
class Bar:
    namespace: str
    id: int

def frobnicate(namespaced: list[T]) -> list[T]:
    for x in namespaced:
        print(x.namespace)
    return namespaced

result1 = frobnicate([Foo('foo')])
result2 = frobnicate([Bar('bar', 1)])

reveal_type(result1)
reveal_type(result2)

然后 mypy 给出:

(py39) Juans-MacBook-Pro:~ juan$ mypy --strict test.py
test.py:27: note: Revealed type is "builtins.list[test.Foo*]"
test.py:28: note: Revealed type is "builtins.list[test.Bar*]"
标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *