如何在 Python 中特化 class(键入泛型)
How to specialize a class in Python (typing generics)
如何为专门的(typing
意义上的)提供不同的定义class?
示例,为什么有用:
TElement = TypeVar('TElement')
class BaseCollection(Generic[TElement]):
name: str
data: List[TElement]
def __add__(self, other: 'BaseCollection[TElement]'):
return CombinedCollection[TElement].from_collections(self, other)
...
class Collection(BaseCollection):
pass
# how do I do this specialization
class Collection[int](BaseCollection[int]):
def sum(self):
return sum(self.data)
# so that CombinedCollection[int] has also the sum method
class CombinedCollection(Collection[TElement]):
@classmethod
def from_collections(cls, *lists: Collection[TElement]):
return CombinedCollection[TElement]('(' + '+'.join(l.name for l in lists) + ')',
[x for l in lists for x in l])
# i.e. I can do
c = Collection[int]('my_collection c', [1,2])
d = Collection[int]('my_collection d', [-1, -2, -3])
cd = c + d
# and now I can do this:
cd.sum()
# -3
cd.name
# (my_collection c+my_collection d)
实际上有一种方法可以做到这一点,但不是创建 class 的“特化”,您需要在 class 定义中定义 class 的所有方法(如果没有类型注释,这就是 Python 的样子),并在方法的 self
参数上添加类型约束:
class Collection(Generic[T]):
def sum(self: "Collection[int]") -> int:
...
a = C[int]([1, 2, 3])
reveal_type(a.sum()) # int
b = C[str](["a", "b", "c"])
reveal_type(b.sum()) # error: Invalid self argument "C[str]" to attribute function "sum"
查看 mypy-play 上的具体示例。
请注意,这仅适用于具体类型,不适用于类型变量。如果将 int
替换为带边界 (TypeVar("T", bound=numbers.Real)
) 或约束 (TypeVar("T", int, float)
) 的 TypeVar
,mypy 似乎会忽略它们并接受任何类型。上面的例子也证明了这一点。我认为这是错误或疏忽。
如何为专门的(typing
意义上的)提供不同的定义class?
示例,为什么有用:
TElement = TypeVar('TElement')
class BaseCollection(Generic[TElement]):
name: str
data: List[TElement]
def __add__(self, other: 'BaseCollection[TElement]'):
return CombinedCollection[TElement].from_collections(self, other)
...
class Collection(BaseCollection):
pass
# how do I do this specialization
class Collection[int](BaseCollection[int]):
def sum(self):
return sum(self.data)
# so that CombinedCollection[int] has also the sum method
class CombinedCollection(Collection[TElement]):
@classmethod
def from_collections(cls, *lists: Collection[TElement]):
return CombinedCollection[TElement]('(' + '+'.join(l.name for l in lists) + ')',
[x for l in lists for x in l])
# i.e. I can do
c = Collection[int]('my_collection c', [1,2])
d = Collection[int]('my_collection d', [-1, -2, -3])
cd = c + d
# and now I can do this:
cd.sum()
# -3
cd.name
# (my_collection c+my_collection d)
实际上有一种方法可以做到这一点,但不是创建 class 的“特化”,您需要在 class 定义中定义 class 的所有方法(如果没有类型注释,这就是 Python 的样子),并在方法的 self
参数上添加类型约束:
class Collection(Generic[T]):
def sum(self: "Collection[int]") -> int:
...
a = C[int]([1, 2, 3])
reveal_type(a.sum()) # int
b = C[str](["a", "b", "c"])
reveal_type(b.sum()) # error: Invalid self argument "C[str]" to attribute function "sum"
查看 mypy-play 上的具体示例。
请注意,这仅适用于具体类型,不适用于类型变量。如果将 int
替换为带边界 (TypeVar("T", bound=numbers.Real)
) 或约束 (TypeVar("T", int, float)
) 的 TypeVar
,mypy 似乎会忽略它们并接受任何类型。上面的例子也证明了这一点。我认为这是错误或疏忽。