ベストアンサー1
これら 2 つの概念は、他の型関連の概念と比べてそれほど関連がありません。
つまり、 a はTypeVar
型シグネチャで使用できる変数であり、同じ未指定の型を複数回参照できます。一方、 a は、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ではこれらの概念について説明しているさらに詳しく説明し、追加のリソースを参照します。
新しいタイプ
ANewType
は、実際に新しい型を作成する作業を実行せずに、または新しいクラス インスタンスを作成するオーバーヘッドを心配せずに、異なる型を宣言する場合に使用します。
型チェッカーでは、 「Name」という名前NewType('Name', int)
のサブクラスを作成しますint
。
実行時には、NewType('Name', int)
はまったくクラスではなく、実際には恒等関数であるため、x is NewType('Name', int)(x)
常に 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
型チェッカーでは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