是否可以解压 类 的列表以用于 Union 类型注释?

Is it possible to unpack a list of classes for use in a Union type annotation?

我有许多映射到数据库的 SQLAlchemy ORM 类。我已经编写了很多函数,这些函数以不同的组合使用其中的许多 类。例如,我可能想从 Tournament table 中获取第一条记录,或者从 Player table 中获取第一条记录。我只需要一个查询,因为查询的字段在 table 之间是相同的。为了维护类型提示,我可以执行以下操作:

def get_first_record(table: Type[Union[Tournament, Player]]):
    # query the table for the first record

如果我不想为其他函数重复类型提示,那么我可以创建一个变量:

Tables = Type[Union[Tournament, Player]]

def get_last_record(table: Tables):
    # query the table for the last record

因为我有大量 table 并且经常添加它们,所以维护这些 Union 变量很痛苦。

巧合的是,为了锁定和解锁 table 的某些组合,我编写了一些函数来在模块中创建 类 的自定义列表。我希望在创建 Union 变量时能够解压缩这些列表,但 Pylance 告诉我 Union 需要两个以上的变量:

tables = [Tournament, Player]
Tables = Type[Union[*tables]] # no bueno :(

有解决办法吗?

我认为不可能完全按照您的要求进行操作:

tables = [Tournament, Player]
Tables = Type[Union[*tables]] # no bueno :(

有关更多详细信息,请参阅这些其他问题:

  • Create Union type without hard-coding in Python3 typing

传递元组 arg(即 Union[tuple(tables)] 有效 python 并将在运行时工作,但不被任何类型检查器(例如 mypy)接受,因为您只能使用文字而不能使用表达式(即函数调用结果)用于定义类型。

可能适合您的替代方法是:

from typing import TypeVar

T = TypeVar('T', bound=django.models.Model)


def get_last_record(table: Type[T]) -> T:
    ...

如果您需要将 get_last_record 的调用限制为特定模型的子集,不幸的是,此注释对您没有帮助 - 您仍然需要定义 Union 个模型以用作bound.

一个可能的变通方法是...而不是定义一个模型列表并尝试从中创建一个联合,相反,例如:


T = Union[Model1, Model2, Model3]

models = list(T.__args__)

但是既然你说 " 我已经写了一些函数来在模块中创建 classes 的自定义列表" 我认为这也不适合你因为函数调用的结果不能作为 mypy 的类型接受。

实际上,可能更适合您的是将模型联合具体化为类型层次结构,作为它们共享的基础 class。

例如而不是:

class Model1(django.models.Model):
    ...

class Model2(django.models.Model):
    ...

class Model3(django.models.Model):
    ...

T = Union[Model1, Model2, Model3]

def get_last_record(table: Type[T]) -> T:
    ...

有:

class OrderableRecord(django.models.Model):
    class Meta:
        abstract = True

class Model1(OrderableRecord):
    ...

class Model2(OrderableRecord):
    ...

class Model3(OrderableRecord):
    ...

T = TypeVar('T', bound=OrderableRecord)

def get_last_record(table: Type[T]) -> T:
    ...