Python 泛型方法的两个参数具有相同的具体类型
Python two parameters of a generic method to have the same concrete type
如何测试函数的参数具有相同的具体类型?
示例:
class A(Generic[T]):
def __init__(p: T):
self._p = p
def get_data(self) -> T:
return self._p
class B(Generic[T]):
def __init__(p: T):
self._p = p
def inc(v: A[T]):
self._p = self._p + v.get_data()
class I(Generic[T]):
def __init__(a: A[T], b: B[T]):
self._a = a
self._b = b
def execute():
self._b.inc(a)
好的:
I(A(1), B(2)).execute()
失败:
I(A(1), B("2")).execute()
所以对我来说,您似乎想使用类型变量/泛型?也就是说,当一个函数被调用时,该类型变量将被绑定到该特定调用。
例如,我们可以有一个函数 head()
,它可以选择 returns 同质列表的头项(Python 对列表没有这个限制,但现在想象一下我们想要):
from typing import TypeVar, Optional, List
T = TypeVar("T", int, float, str)
def head(lst: List[T]) -> Optional[T]:
if lst:
return lst[0]
return None
print(head([1, 2]))
print(head(["koi"]))
print(head([]))
现在,这些列表允许使用 str、float 或 int 类型,但它们
必须是同质的。因此,类型签名基本上表示“head 采用字符串、整数或浮点数的列表,无论列表中的项目类型是什么,return 值(如果存在)也将是该类型”
请注意,这与联合类型完全不同,例如。你可以
T = Union[str, float, int]
def head(lst: List[T]) -> Optional[T]:
...
但它不会像你想要的那样工作;根据类型,即使列表仅包含字符串,returning 一个 int 仍然可以。
更新:正如@MisterMiyagi 在下面的评论中所提到的,这仍然需要用户了解允许的类型。
对于您的用例(使用 classes),这应该没问题(尝试使用最少的示例):
from typing import TypeVar, Generic
T = TypeVar("T")
class A(Generic[T]):
def a(self, a: T, b: T) -> T:
return a
print(A[int]().a(1, 2))
print(A[float]().a(32.1, 2))
print(A[str]().a("koi", "bar"))
# print(A[int]().a(1, "bar")) -- does not pass type checker
这里的关键区别是您在实际调用它们时仍然需要传递类型,但在定义泛型时它们不需要存在 class.
查看 https://mypy.readthedocs.io/en/stable/generics.html 了解更多信息。
如何测试函数的参数具有相同的具体类型?
示例:
class A(Generic[T]):
def __init__(p: T):
self._p = p
def get_data(self) -> T:
return self._p
class B(Generic[T]):
def __init__(p: T):
self._p = p
def inc(v: A[T]):
self._p = self._p + v.get_data()
class I(Generic[T]):
def __init__(a: A[T], b: B[T]):
self._a = a
self._b = b
def execute():
self._b.inc(a)
好的:
I(A(1), B(2)).execute()
失败:
I(A(1), B("2")).execute()
所以对我来说,您似乎想使用类型变量/泛型?也就是说,当一个函数被调用时,该类型变量将被绑定到该特定调用。
例如,我们可以有一个函数 head()
,它可以选择 returns 同质列表的头项(Python 对列表没有这个限制,但现在想象一下我们想要):
from typing import TypeVar, Optional, List
T = TypeVar("T", int, float, str)
def head(lst: List[T]) -> Optional[T]:
if lst:
return lst[0]
return None
print(head([1, 2]))
print(head(["koi"]))
print(head([]))
现在,这些列表允许使用 str、float 或 int 类型,但它们 必须是同质的。因此,类型签名基本上表示“head 采用字符串、整数或浮点数的列表,无论列表中的项目类型是什么,return 值(如果存在)也将是该类型”
请注意,这与联合类型完全不同,例如。你可以
T = Union[str, float, int]
def head(lst: List[T]) -> Optional[T]:
...
但它不会像你想要的那样工作;根据类型,即使列表仅包含字符串,returning 一个 int 仍然可以。
更新:正如@MisterMiyagi 在下面的评论中所提到的,这仍然需要用户了解允许的类型。
对于您的用例(使用 classes),这应该没问题(尝试使用最少的示例):
from typing import TypeVar, Generic
T = TypeVar("T")
class A(Generic[T]):
def a(self, a: T, b: T) -> T:
return a
print(A[int]().a(1, 2))
print(A[float]().a(32.1, 2))
print(A[str]().a("koi", "bar"))
# print(A[int]().a(1, "bar")) -- does not pass type checker
这里的关键区别是您在实际调用它们时仍然需要传递类型,但在定义泛型时它们不需要存在 class.
查看 https://mypy.readthedocs.io/en/stable/generics.html 了解更多信息。