Search code examples
pythonpython-typingpyright

How does typing.Type work in Python? When can variables be used as types?


I am using Python 3.11 and Pylance for this.

class Dog:
    pass

Example A:

DogType: type[Dog] = Dog # type[Dog]

AnotherDogType: type[DogType] = Dog # Error
#                    ^^^^^^^ variable not allowed in type expression

Example B:

DogType = Dog # type[Dog]

AnotherDogType: type[DogType] = Dog # Ok

I am wondering why I get the error for ExampleA.AnotherDogType. DogType is type[Dog] when I hover over both variables in vscode.


Solution

  • In the case of:

    DogType = Dog
    

    That is being recognized as a type alias by pylance. You can even see this when you hover over it:

    enter image description here

    Python's type annotation system is relatively new, and still currently evolving. This was the original way to create a type alias. From my recollection, this was never adequatly specified, and different type checkers have treated assigning types to a bare variable differently when it occurs in different context (e.g. in a class definition).

    Later, the typing.TypeAlias type hint was added to make this less ambiguous, and even more recently in Python 3.12, a type statement was added. Type statemens should be preferred over the bare variable assignment way of doing things, and typing.TypeAlias should only be used for backwards compatibilty. Code written for Python 3.12+ should use type statements to create type aliases.

    When you explicitly annotate it with DogType: type[Dog] = Dog, then it is no longer a type alias, it is treated as just a regular variable that will hold type objects.

    As an aside, I just want to reiterate something that was stated in the comments, but nesting classes like this almost never makes any sense.