Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What the code '_T = TypeVar('_T')' means in a *.pyi file?

I'm new to Python annotation (type hints). I noticed that many of the class definitions in pyi files inherit to Generic[_T], and _T = TypeVar('_T').

I am confused, what does the _T mean here?

from typing import Generic, TypeVar

_T = TypeVar('_T')

class Base(Generic[_T]): pass
like image 239
EvinK Avatar asked Aug 19 '19 07:08

EvinK


People also ask

What does the _t mean in typevar mean?

I am confused, what does the _T mean here? from typing import Generic, TypeVar _T = TypeVar ('_T') class Base (Generic [_T]): pass _ is just means that that variable is protected type. I recommend reading through the entire built-in typing module documentation.

What is a Pyi file and how do I use it?

What is a PYI file? A PYI file is a code stub used to specify type hints for a Python module. Python type checkers can read PYI files and use them to warn developers of potential type mismatches. PYI files have the same syntax as regular Python modules; they are typically stored alongside the module for which they contain type hints.

What is typevar in C++?

Specifically, typing.TypeVar is used to specify that multiple possible types are allowed. If no specific types are specified, then any type is valid. from typing import TypeVar T = TypeVar ('T') # <-- 'T' can be any type A = TypeVar ('A', str, int) # <-- 'A' will be either str or int

What does the I in Python I stand for?

I think the i in .pyi stands for "Interface". Definition for Interface in Java: An interface in the Java programming language is an abstract type that is used to specify a behaviour that classes must implement. From Python typeshed github repository:


1 Answers

I recommend reading through the entire built-in typing module documentation.


typing.TypeVar

Basic Usage

Specifically, typing.TypeVar is used to specify that multiple possible types are allowed. If no specific types are specified, then any type is valid.

from typing import TypeVar

T = TypeVar('T')            # <-- 'T' can be any type
A = TypeVar('A', str, int)  # <-- 'A' will be either str or int

But, if T can be any type, then why create a typing.TypeVar like that, when you could just use typing.Any for the type hint?

The reason is so you can ensure that particular input and output arguments have the same type, like in the following examples.

A Dict Lookup Example

from typing import TypeVar, Dict
Key = TypeVar('Key')
Value = TypeVar('Value')

def lookup(input_dict: Dict[Key, Value], key_to_lookup: Key) -> Value:
    return input_dict[key_to_loopup]

This appears to be a trivial example at first, but these annotations require that the types of the keys in input dictionary are the same as the key_to_lookup argument, and that the type of the output matches the type of the values in the dict as well.

The keys and values as a whole could be different types, and for any particular call to this function, they could be different (because Key and Value do not restrict the types), but for a given call, the keys of the dict must match the type of the lookup key, and the same for the values and the return type.

An Addition Example

If you create a new TypeVar and limit the types to float and int:

B = TypeVar('B', float, int)

def add_x_and_y(x: B, y: B) -> B:
    return x + y

This function requires that x and y either both be float, or both be int, and the same type must be returned. If x were a float and y were an int, the type checking should fail.


typing.Generic

I'm a little more sketchy on this one, but the typing.Generic (links to the official docs) Abstract Base Class (ABC) allows setting up a Class that has a defined type hint. They have a good example in the linked docs.

In this case they are creating a completely generic type class. If I understand correctly, this allows using Base[AnyName] as a type hint elsewhere in the code and then one can reuse AnyName to represent the same type elsewhere within the same definition (i.e. within the same code scope).

I suppose this would be useful to avoid having to use TypeVar repeatedly, you can basically create new TypeVars at will by just using the Base class as a type hint, as long as you just need it for the scope of that local definition.

like image 54
LightCC Avatar answered Oct 16 '22 08:10

LightCC