В чем разница между TypeVar и NewType? - PullRequest
1 голос
/ 07 ноября 2019

TypeVar и NewType кажутся связанными, но я не уверен, когда я должен использовать каждый из них или какая разница во время выполнения и статически.

1 Ответ

1 голос
/ 09 ноября 2019

Эти два понятия не связаны между собой больше, чем любые другие понятия, связанные с типами.

Короче говоря, 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 описывает эти концепции более подробно и ссылается на дополнительные ресурсы.

NewType

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
...