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 了解更多信息。