1. ホーム
  2. python

TypeVarとNewTypeの違いは何ですか?

2023-12-28 14:02:28

質問

TypeVar そして NewType は関連しているように見えますが、それぞれをいつ使えばいいのか、実行時と静的時の違いは何なのか、よくわかりません。

どのように解決するのですか?

この2つの概念は、他の型に関連する概念と同じように、何の関係もありません。

要するに TypeVar は型シグネチャで使える変数で、同じ不特定の型を複数回参照することができるのに対して NewType は、ある値をそれ自身の型として扱うように型チェッカに伝えるために使われます。

型変数

単純化すると、型変数は、それがどの型であるかを正確に指定することなく、同じ型を複数回参照することができます。

定義では、単一の型変数は常に同じ値をとります。

# (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')

型変数が無ければ、このように get_one または ValueHolder.get .

には他にもいくつかのオプションがあります。 TypeVar . より多くの型を渡すことで、可能な値を制限することができます (例: TypeVar(name, int, str) のように)、あるいは型変数のすべての値がその型のサブタイプでなければならないように上限を与えることができます(例えば TypeVar(name, bound=int) ).

さらに、型変数を宣言するときに、共変量、共変量、またはどちらでもないかを決めることができます。これは本質的に、サブクラスやスーパークラスが一般的な型の代わりにいつ使用できるかを決定するものです。 PEP 484 では、これらの概念について説明しています。 をより詳細に説明し、追加のリソースを参照しています。

新しいタイプ

A NewType は、実際に新しい型を作成したり、新しいクラスのインスタンスを作成するオーバーヘッドを心配することなく、個別の型を宣言したいときのためにあります。

タイプチェッカーでは NewType('Name', int) のサブクラスを作成します。 int という名前のサブクラスを作成します。

実行時に NewType('Name', int) は全くクラスではなく、実際には ID 関数なので 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.1 の時点では、その の実装が追加されました。 はほぼ以下の通りです。

def NewType(name, type_):
    def identity(x):
        return x
    identity.__name__ = name
    return identity