为何List[int]不是List[float]的子类型?从LSP视角解析
Python中List[int]不是List[float]子类型的LSP合理性解析
首先得明确:里氏替换原则(LSP)的核心不是“两个类型有相同的方法集”,而是子类型必须完全遵守父类型的行为契约——当你用子类型实例替换父类型实例时,所有针对父类型的合法操作,在子类型上执行都不能破坏程序的正确性。
问题的关键:可变容器的行为契约冲突
Python的list是可变容器,List[float]作为父类型,它的行为契约包含:
- 可以向其中添加任意
float类型的元素 - 容器内的所有元素都应该是
float(或其子类型)
而List[int]的行为契约则是:
- 只能向其中添加
int类型的元素 - 容器内的所有元素都应该是
int
当你把List[int]当作List[float]传入期望父类型的函数时,函数会按照List[float]的契约执行操作——比如添加一个float值:
from typing import List def add_pi(lst: List[float]) -> None: lst.append(3.14) # 符合List[float]的契约:添加float是合法操作 int_list: List[int] = [1, 2, 3] add_pi(int_list) # 类型检查器会报错,但强行运行会导致int_list混入float print(int_list) # 输出 [1, 2, 3, 3.14],彻底破坏了int_list的类型完整性
为什么方法集相同仍违反LSP?
List[int]和List[float]的方法签名看起来完全一致,但它们的方法前置条件不同:
List[float].append的前置条件是“参数为float或其子类型”List[int].append的前置条件是“参数为int或其子类型”
LSP要求,子类型方法的前置条件不能比父类型更严格——但这里List[int].append的前置条件(只能传int)比List[float].append(可以传float)更严格,这就导致:父类型允许的操作(传float到append)在子类型中是非法的,替换后程序的正确性被破坏,直接违反了LSP。
结合PEP 483的判定逻辑
PEP 483中关于子类型判定的第二个条件,核心是可变容器必须是不变类型。因为如果允许List[int]作为List[float]的子类型(协变),就会出现上述的类型安全漏洞——可变容器的协变会导致父类型的操作破坏子类型的内部状态,违反LSP的核心要求。
内容的提问来源于stack exchange,提问作者ilovewt
相关产品推荐
相关产品推荐

