使用类型参数从 typing.Union 派生

Deriving from typing.Union with type arguments

我正在尝试从 typing.Union 派生一个 class,使用类型参数进行参数化,但我收到一个我不理解的 TypeError。

这些都很好:

import typing

class Foo(typing.Dict[str, int]): pass
class Bar(typing.Union[str]): pass
typing.Union[str, int]

(当然,Union[str] 是多余的,可以只是 str。)

但下面的加注 TypeError: __init__() takes 2 positional arguments but 4 were given:

class Foo(typing.Union[str, int]): pass

class Foo(typing.Optional[str]) 引发相同的错误,这是有道理的,因为 typing.Optional[str] 等同于 typing.Union[NoneType, str].

另一方面,如果有某些原因需要避免 subclassing Union 而 subclassing DictList 很好(我在 this portion of the Mypy docs 之后模糊地建模我的代码),我想知道它是什么。

According to the docs,您不能子类化或实例化联合。

class Foo(typing.Union[str, int]):
    pass

def f(foo: Foo):
    print(foo)
    
f(1)

加注

Traceback (most recent call last):
  File "<string>", line 3, in <module>
File "/usr/lib/python3.8/typing.py", line 317, in __new__
    raise TypeError(f"Cannot subclass {cls!r}")
TypeError: Cannot subclass <class 'typing._SpecialForm'>

相反,您可以创建类型别名:

Foo = typing.Union[str, int]

def f(foo: Foo):
    print(foo)
    
f(1)

按预期工作。


你可能会问为什么

class Bar(typing.Union[str]):
    pass

有效。如果您在 typing.Union 创建时查看 at the source code (__new__),您将看到以下代码段:

if origin is Union:
    parameters = _remove_dups_flatten(parameters)
    # It's not a union if there's only one type left.
    if len(parameters) == 1:
        return parameters[0]

也就是说,如果一个typing.Union只有一个类型,那么它就等价于这个类型。事实上,

print(isinstance(Bar(), str))

输出真。