Эти два понятия не связаны между собой больше, чем любые другие понятия, связанные с типами.
Короче говоря, TypeVar
- это переменная, которую вы можете использовать в сигнатурах типов, чтобы вы могли ссылаться на одно и то же неопределенноевведите более одного раза, в то время как NewType
используется, чтобы сообщить контролеру типов, что некоторые значения должны рассматриваться как их собственный тип.
Для упрощенияпеременные типа позволяют ссылаться на один и тот же тип более одного раза, не указывая точно, какой это тип.
В определении переменная одного типа всегда принимает одно и то же значение.
from typing import TypeVar, Generic, List
# (This code will type check, but it won't run.)
# 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')
Без переменных типа не было бы хорошего способа объявить тип get_one
или ValueHolder.get
.
. Есть несколько других опций для TypeVar
. Вы можете ограничить возможные значения, передав больше типов (например, TypeVar(name, int, str)
), или вы можете задать верхнюю границу, чтобы каждое обязательное значение переменной типа должно быть подтипом этого типа (например, TypeVar(name, bound=int)
).
Кроме того, вы можете решить, является ли переменная типа ковариантной, контравариантной или нет, когда вы объявляете ее. Это по существу решает, когда подклассы или суперклассы могут использоваться вместо универсального типа. PEP 484 описывает эти концепции более подробно и ссылается на дополнительные ресурсы.
A NewType
предназначен для случаев, когда вы хотитеобъявляйте отдельный тип, фактически не выполняя работу по созданию нового типа или не беспокоясь о накладных расходах на создание новых экземпляров класса.
В средстве проверки типов NewType('Name', int)
создает подкласс int
с именем "Name". "
Во время выполнения NewType('Name', int)
вообще не является классом;на самом деле это тождественная функция, поэтому x is NewType('Name', int)(x)
всегда истинно.
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
Для проверки типов UserId
выглядит примерно так:
class UserId(int): pass
Но во время выполнения,UserId
в основном это просто:
def UserId(x): return x
Почти ничего нет, кроме NewType
во время выполнения. Начиная с Python 3.8, его реализация выглядит почти следующим образом:
def NewType(name, type_):
def identity(x):
return x
identity.__name__ = name
return identity