Python 实现协议的通用类型
Python generic type that implements protocol
对象 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`
...
这很好用,但它允许传递不具有属性 namespace
的类型 X
的对象而不会出现任何检查错误。
然后我创建了一个协议并更改了函数以使用该协议:
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]
我如何结合泛型和协议,使我的函数 returns 成为 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`
...
干杯!
使用协议作为绑定的绑定类型变量。考虑以下模块:
(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*]"
对象 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`
...
这很好用,但它允许传递不具有属性 namespace
的类型 X
的对象而不会出现任何检查错误。
然后我创建了一个协议并更改了函数以使用该协议:
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]
我如何结合泛型和协议,使我的函数 returns 成为 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`
...
干杯!
使用协议作为绑定的绑定类型变量。考虑以下模块:
(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*]"