有没有办法在 Python 输入中为 Union 的初始值设定项提供序列

Is there a way to give a sequence to initializer of Union in Python typing

我的代码如下所示:

MY_SPECIAL_CLASSES = (Foo, Bar, Spam, Eggs)

我有很多函数将其中任何一个作为输入参数,

所以他们的签名是例如:

def whatever(obj: Union[Foo, Bar, Spam, Eggs]) -> None:

对我来说,显而易见的解决方案 - 只需使用公共超类 - 在 PEP484 中被明确声明为禁忌(强调我的)

By default type variables are considered invariant , which means that arguments for arguments annotated with types like List[Employee] must exactly match the type annotation -- no subclasses or superclasses of the type parameter (in this example Employee ) are allowed.

def something(obj: Union[*MY_SPECIAL_CLASSES]) -> None:

不起作用,我必须做类似的事情:

UNION_OF_MY_SPECIAL_CLASSES = Union[Foo, Bar, Spam, Eggs]
def another(obj: UNION_OF_MY_SPECIAL_CLASSES) -> UNION_OF_MY_SPECIAL_CLASSES:

对我来说,这很丑陋 - 并且明显违反了 DRY。

为了避免 DRY,我可以在我的定义中使用 dunder-attribute __union_set_params__,但对我来说这种方式看起来有点不卫生和倒退,例如

UNION_OF_MY_SPECIAL_CLASSES = Union[Foo, Bar, Spam, Eggs]
MY_SPECIAL_CLASSES = tuple(UNION_OF_MY_SPECIAL_CLASSES.__union_set_params__)

有没有更优雅的方法?

你误读了 PEP。类型变量的默认不变性意味着在需要 Foo[Superclass] 的地方传递 Foo[Subclass] 是错误的,但是可以将 Subclass 传递给注释为 SuperClass 的参数.

只要你的函数接受公共超类的任何实例(所以没有你想要拒绝的第 5 个子类或任何东西),你应该可以用超类注释这些参数。