Search code examples
pythonpython-typing

Type of Union or Union of Types


In Python, is Type[Union[A, B, C]] the same as Union[Type[A], Type[B], Type[C]]? I think they are equivalent, and the interpreter seems to agree.

ChatGPT (which, from my past experience, tends to be wrong with this type of questions) disagrees so I was wondering which one is more correct.

To be clear: I want a union of the types of A, B or C, not a union of instances of A, B or C. The first option is shorter and IMHO more readable.

In other words, given these definitions:

class A: pass
class B: pass
class C: pass

def foo(my_class: Type[Union[A, B, C]]): pass

I expect this usage to be correct:

foo(A)   # pass the class A itself

But not this one:

foo(A()) # pass an instance of A

Solution

  • They are the same. You can use reveal_type and check.

    class A: ...
    class B: ...
    class C: ...
    
    def something(a: type[A | B | C]) -> None:
        reveal_type(a)
    
    def something_else(b: type[A] | type[B]| type[C]) -> None:
        reveal_type(b)
    
    mypy main.py
    main.py:6: note: Revealed type is "Union[type[main.A], type[main.B], type[main.C]]"
    main.py:9: note: Revealed type is "Union[type[main.A], type[main.B], type[main.C]]"
    
    pyright main.py 
      main.py:6:17 - information: Type of "a" is "type[A] | type[B] | type[C]"
      main.py:9:17 - information: Type of "b" is "type[A] | type[B] | type[C]"
    

    Edit:

    Older syntax

    from typing import Union, Type
    class A: ...
    class B: ...
    class C: ...
    
    def something(a: type[A | B | C]) -> None:
        reveal_type(a)
    
    def something_else(b: type[A] | type[B]| type[C]) -> None:
        reveal_type(b)
    
    def old_something(c: Type[Union[A, B, C]]) -> None:
        reveal_type(c)
    
    def old_something_else(d: Union[Type[A], Type[B], Type[C]]) -> None:
        reveal_type(d)
    
    mypy main.py
    main.py:7: note: Revealed type is "Union[type[main.A], type[main.B], type[main.C]]"
    main.py:10: note: Revealed type is "Union[type[main.A], type[main.B], type[main.C]]"
    main.py:13: note: Revealed type is "Union[type[main.A], type[main.B], type[main.C]]"
    main.py:16: note: Revealed type is "Union[type[main.A], type[main.B], type[main.C]]"
    
    pyright main.py
      main.py:7:17 - information: Type of "a" is "type[A] | type[B] | type[C]"
      main.py:10:17 - information: Type of "b" is "type[A] | type[B] | type[C]"
      main.py:13:17 - information: Type of "c" is "type[A] | type[B] | type[C]"
      main.py:16:17 - information: Type of "d" is "type[A] | type[B] | type[C]"