Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between TypeVar and NewType?

TypeVar and NewType seem related but I'm not sure when I'm supposed to use each or what the difference is at runtime and statically.

like image 221
Hatshepsut Avatar asked Nov 07 '19 19:11

Hatshepsut


People also ask

Should I use type hints Python?

Type hints work best in modern Pythons. Annotations were introduced in Python 3.0, and it's possible to use type comments in Python 2.7. Still, improvements like variable annotations and postponed evaluation of type hints mean that you'll have a better experience doing type checks using Python 3.6 or even Python 3.7.

What are type hints?

Introduction to Python type hints It means that you need to declare types of variables, parameters, and return values of a function upfront. The predefined types allow the compilers to check the code before compiling and running the program.

What is type annotation in Python?

Type annotations — also known as type signatures — are used to indicate the datatypes of variables and input/outputs of functions and methods. In many languages, datatypes are explicitly stated. In these languages, if you don't declare your datatype — the code will not run.

What is type checking in Python?

Python is a dynamically typed language. This means that the Python interpreter does type checking only as code runs, and that the type of a variable is allowed to change over its lifetime.


Video Answer


1 Answers

The two concepts aren't related any more than any other type-related concepts.

In short, a TypeVar is a variable you can use in type signatures so you can refer to the same unspecified type more than once, while a NewType is used to tell the type checker that some values should be treated as their own type.

Type Variables

To simplify, type variables let you refer to the same type more than once without specifying exactly which type it is.

In a definition, a single type variable always takes the same value.

# (This code will type check, but it won't run.) from typing import TypeVar, Generic, List, Tuple  # Two type variables, named T and R T = TypeVar('T') R = TypeVar('R')  # Put in a list of Ts and get out one T def get_one(x: List[T]) -> T: ...  # Put in a T and an R, get back an R and a T def swap(x: T, y: R) -> Tuple[R, T]:     return y, x  # A simple generic class that holds a value of type T class ValueHolder(Generic[T]):     def __init__(self, value: T):         self.value = value     def get(self) -> T:         return self.value  x: ValueHolder[int] = ValueHolder(123) y: ValueHolder[str] = ValueHolder('abc') 

Without type variables, there wouldn't be a good way to declare the type of get_one or ValueHolder.get.

There are a few other options on TypeVar. You can restrict the possible values by passing in more types (e.g. TypeVar(name, int, str)), or you can give an upper bound so every value of the type variable must be a subtype of that type (e.g. TypeVar(name, bound=int)).

Additionally, you can decide whether a type variable is covariant, contravariant, or neither when you declare it. This essentially decides when subclasses or superclasses can be used in place of a generic type. PEP 484 describes these concepts in more detail, and refers to additional resources.

NewType

A NewType is for when you want to declare a distinct type without actually doing the work of creating a new type or worry about the overhead of creating new class instances.

In the type checker, NewType('Name', int) creates a subclass of int named "Name."

At runtime, NewType('Name', int) is not a class at all; it is actually the identity function, so x is NewType('Name', int)(x) is always true.

from typing import NewType  UserId = NewType('UserId', int)  def get_user(x: UserId): ...  get_user(UserId(123456)) # this is fine get_user(123456) # that's an int, not a UserId  UserId(123456) + 123456 # fine, because UserId is a subclass of int 

To the type checker, UserId looks something like this:

class UserId(int): pass 

But at runtime, UserId is basically just this:

def UserId(x): return x 

There's almost nothing more than that to a NewType at runtime. As of Python 3.8.1, its implementation is almost exactly as follows:

def NewType(name, type_):     def identity(x):         return x     identity.__name__ = name     return identity 
like image 187
jirassimok Avatar answered Sep 20 '22 03:09

jirassimok