泛型类型
泛型让类型定义更灵活、可复用。例如 list[int] 和 list[str] 都是 list 的泛型实例,只是元素类型不同。
TypeVar:类型变量
TypeVar 定义一个类型参数,在调用时绑定到具体类型:
python
from typing import TypeVar
T = TypeVar('T')
def first(items: list[T]) -> T:
return items[0]
# T 被推断为 int
number = first([1, 2, 3]) # number: int
# T 被推断为 str
name = first(["Alice", "Bob"]) # name: str不使用泛型的问题:
python
def first(items: list) -> object: # 返回 object,丢失类型信息
return items[0]
number = first([1, 2, 3])
print(number + 10) # 类型检查器警告:object 不支持 +泛型函数
多个类型参数
python
from typing import TypeVar
K = TypeVar('K')
V = TypeVar('V')
def make_pair(key: K, value: V) -> tuple[K, V]:
return (key, value)
pair1 = make_pair("name", "Alice") # tuple[str, str]
pair2 = make_pair(1, "Alice") # tuple[int, str]类型约束
限制 TypeVar 只能是特定类型之一:
python
from typing import TypeVar
# 只能是 int 或 float
Number = TypeVar('Number', int, float)
def double(value: Number) -> Number:
return value * 2
print(double(5)) # OK: int
print(double(3.14)) # OK: float
print(double("hi")) # 类型错误类型边界(Bound)
约束类型必须是某个类的子类:
python
from typing import TypeVar
class Animal:
def make_sound(self) -> str:
return "..."
class Dog(Animal):
def make_sound(self) -> str:
return "Woof"
class Cat(Animal):
def make_sound(self) -> str:
return "Meow"
T = TypeVar('T', bound=Animal)
def get_sound(animal: T) -> str:
return animal.make_sound() # 类型检查器知道 T 有 make_sound
dog = Dog()
print(get_sound(dog)) # OK
# get_sound("hello") # 错误:str 不是 Animal 的子类泛型类
定义泛型类
python
from typing import Generic, TypeVar
T = TypeVar('T')
class Stack(Generic[T]):
def __init__(self) -> None:
self._items: list[T] = []
def push(self, item: T) -> None:
self._items.append(item)
def pop(self) -> T:
return self._items.pop()
def is_empty(self) -> bool:
return len(self._items) == 0
# 使用
int_stack: Stack[int] = Stack()
int_stack.push(1)
int_stack.push(2)
print(int_stack.pop()) # 2
str_stack: Stack[str] = Stack()
str_stack.push("hello")
# str_stack.push(42) # 类型错误多个类型参数
python
from typing import Generic, TypeVar
K = TypeVar('K')
V = TypeVar('V')
class Pair(Generic[K, V]):
def __init__(self, key: K, value: V) -> None:
self.key = key
self.value = value
def get_key(self) -> K:
return self.key
def get_value(self) -> V:
return self.value
pair = Pair("name", 42) # Pair[str, int]
print(pair.get_key()) # str
print(pair.get_value()) # int协变与逆变
不变(Invariant)
默认情况下,泛型类型是不变的:
python
class Animal:
pass
class Dog(Animal):
pass
# list 是不变的
def feed_animals(animals: list[Animal]) -> None:
pass
dogs: list[Dog] = [Dog()]
# feed_animals(dogs) # 类型错误!list[Dog] 不是 list[Animal]原因:如果允许传入 list[Dog],函数内部可能添加 Cat,破坏类型安全:
python
def feed_animals(animals: list[Animal]) -> None:
animals.append(Cat()) # 如果 animals 是 list[Dog],这会出错协变(Covariant)
T 是协变的:如果 Dog 是 Animal 的子类,则 Container[Dog] 是 Container[Animal] 的子类。
只读容器可以协变:
python
from typing import TypeVar
T_co = TypeVar('T_co', covariant=True)
class ReadOnlyBox(Generic[T_co]):
def __init__(self, value: T_co) -> None:
self._value = value
def get(self) -> T_co:
return self._value
def process_animal(box: ReadOnlyBox[Animal]) -> None:
print(box.get())
dog_box: ReadOnlyBox[Dog] = ReadOnlyBox(Dog())
process_animal(dog_box) # OK,因为 ReadOnlyBox 是协变的逆变(Contravariant)
T 是逆变的:如果 Dog 是 Animal 的子类,则 Container[Animal] 是 Container[Dog] 的子类。
只写容器可以逆变:
python
from typing import TypeVar
T_contra = TypeVar('T_contra', contravariant=True)
class Feeder(Generic[T_contra]):
def feed(self, animal: T_contra) -> None:
print(f"Feeding {animal}")
def train_dog(feeder: Feeder[Dog]) -> None:
feeder.feed(Dog())
animal_feeder: Feeder[Animal] = Feeder()
train_dog(animal_feeder) # OK,因为 Feeder 是逆变的规则总结:
- 不变(默认):可读可写
- 协变(
covariant=True):只读(输出位置) - 逆变(
contravariant=True):只写(输入位置)
实战案例:泛型容器
python
from typing import Generic, TypeVar, Optional
T = TypeVar('T')
class LinkedListNode(Generic[T]):
def __init__(self, value: T) -> None:
self.value = value
self.next: Optional[LinkedListNode[T]] = None
class LinkedList(Generic[T]):
def __init__(self) -> None:
self.head: Optional[LinkedListNode[T]] = None
def append(self, value: T) -> None:
new_node = LinkedListNode(value)
if self.head is None:
self.head = new_node
else:
current = self.head
while current.next is not None:
current = current.next
current.next = new_node
def to_list(self) -> list[T]:
result: list[T] = []
current = self.head
while current is not None:
result.append(current.value)
current = current.next
return result
# 使用
numbers = LinkedList[int]()
numbers.append(1)
numbers.append(2)
numbers.append(3)
print(numbers.to_list()) # [1, 2, 3]
names = LinkedList[str]()
names.append("Alice")
names.append("Bob")
print(names.to_list()) # ['Alice', 'Bob']泛型装饰器
python
from typing import TypeVar, Callable
import time
T = TypeVar('T')
def timer(func: Callable[..., T]) -> Callable[..., T]:
def wrapper(*args, **kwargs) -> T:
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
print(f"{func.__name__} took {elapsed:.4f}s")
return result
return wrapper
@timer
def slow_function(n: int) -> int:
time.sleep(1)
return n * 2
result = slow_function(5) # result: int小结
- TypeVar 定义类型变量,实现泛型
- Generic[T] 创建泛型类
- Bound 约束类型必须是某个类的子类
- 协变(covariant)用于只读容器
- 逆变(contravariant)用于只写容器
- 默认是不变(invariant)
下一节学习 Protocol,它提供结构化子类型。
练习:答案