本文介绍在 python 类型检查中,如何正确处理父类字段被子类 @property 覆盖导致的类型冲突问题,通过抽象属性(@abstractmethod + @property)实现 lsp 兼容
的类型声明。
在面向对象设计中,若父类定义了一个可读写的实例属性(如 value: int),而子类将其重写为只读 @property,虽然运行时可能正常工作,但会违反里氏替换原则(Liskov Substitution Principle, LSP)——因为类型系统无法保证所有 A 的子类都支持对 value 的赋值操作。Pyright 报错 Type "property" cannot be assigned to type "int" 正是对此不兼容性的精准提示。
根本解决方案不是“绕过检查”,而是在类型层面统一契约:将 value 明确定义为一个只读接口,允许不同子类以不同方式实现(字段、计算属性、缓存逻辑等),同时确保所有 isinstance(a, A) 的实例调用 a.value 均返回 int。
推荐做法是使用抽象基类(ABC)配合抽象属性:
from abc import ABC, abstractmethod
class A(ABC):
@property
@abstractmethod
def value(self) -> int:
"""获取整数值;具体实现由子类提供。"""
...
class B(A):
@property
def value(self) -> int:
return 3
class C(A):
def __init__(self, value: int) -> None:
self._value = value
@property
def value(self) -> int:
return self._value✅ 优势说明:
⚠️ 注意事项:
总结:类型系统不是障碍,而是设计反馈。当出现“运行时 OK、类型报错”时,往往是接口抽象不足的信号。用 ABC + @property @abstractmethod 主动建模“只读访问契约”,是兼顾类型安全、运行时灵活性与面向对象原则的最佳实践。