什么是协变(Covariant)与逆变(Contravariant)?
代码来源: longchain_core/runnables/utils.py Line 38
from typing import TypeVar
"""
"""
Input = TypeVar("Input", contravariant=True)
0 解释
类型 | 含义 |
协变(Covariant) | 如果 Dog 是 Animal 的子类,那么 List[Dog] 也可以当作 List[Animal] 使用。 |
逆变(Contravariant) | 如果 Dog 是 Animal 的子类,那么 SomeClass[Animal] 可以当作 SomeClass[Dog] 使用。 |
1 举个例子:
class Animal:passclass Dog(Animal):passdef feed(animal: Animal):print("Feeding an animal")# 假设我们有一个接受 Dog 的函数
def take_dog(handler: SomeClass[Dog]):pass
如果你有一个 SomeClass[Animal] 实例,由于它是 SomeClass[Dog] 的超类(因为 Input 是逆变),你可以把它传给需要 SomeClass[Dog] 的地方。
2 为什么设置 contravariant=True?
当你希望某个泛型类或协议接受的输入类型是可以“向上兼容”的时候,就使用逆变。
常见于:
- 函数参数
- 输入流(如请求数据)
- 配置对象
例如,在 LangChain 中,某些 Runnable(可执行对象)接收输入数据,这些数据可能是不同类型,但只要符合输入要求即可。
3 小结
概念 | 说明 |
TypeVar("Input") | 定义一个泛型类型变量,表示“任意类型” |
contravariant=True | 设置该类型变量为逆变,意味着可以用父类型的实例替代子类型 |
应用场景 | 函数参数、输入处理等需要“宽泛匹配”的情况 |
这样设计可以让类型系统更灵活,也更贴近实际使用场景。
4 创建通用类型参数 TypeVar 一些其他的代码示例
# TypeVar 类型变量
# 创建通用类型参数
# 场景: 泛型函数/类的类型参数化:比如创建一个函数,无论是处理整数\字符串还是自定义对象
from typing import TypeVar,SequenceT = TypeVar('T') # 无约束类型
Num = TypeVar('Num', int, float) # 受限类型def first(item:Sequence[T]) -> T:return item[0]def sums(values:Sequence[Num])->Num:return sum(values)#####
def get_first_item(items:T) -> T:if items:return items[0]raise ValueError("列表为空")numbers = [1,2,3,4,5]
words = ['apple','banana','cherry','fruit']print(get_first_item(numbers))
print(get_first_item(words))