了解 LSP Python

Understanding LSP Python

所以 LSP 说,如果 S 是 T 的子类型,那么 S 的任何实例都应该能够替换 T 的任何实例,而不会改变该程序的任何所需属性。

这是否意味着这会使 LSP 失败,因为当您执行 dev_1.print_name()(将 subclass 的实例替换为基础 class -ish 的实例)时,您得到一个意想不到的结果(失败),因为你还没有初始化名字?

@dataclass
class Employee:
    name: str

    def print_name(self):
        print(self.name)

class Developer(Employee):
    def __init__(self, work_from_home: bool):
        self.work_from_home = work_from_home
    

dev_1 = Developer(True)
dev_1.print_name()

解决这个问题的方法是将 Developer class 更改为类似这样的内容,以便与 Employee class?[=15 的所有方法兼容=]

class Developer(Employee):
    def __init__(self, work_from_home: bool, name:str):
        self.work_from_home = work_from_home
        super().__init__(name)

你是对的。在编写代码时,创建 Employee 需要为其 name 属性赋值。但是正如所写,您的代码在创建 Developer 时不会初始化 name。正如您所说,这导致 Developer 对象的行为不像 Employee 对象,因此它违反了 LSP。

您添加一个为 name 属性取值的构造函数的解决方案确实解决了问题。获得相同行为的标准方法是将 Developer 也注释为数据 class 以便您免费获得正确的构造函数:

@dataclass
class Employee:
    name: str

    def print_name(self):
        print(self.name)

@dataclass
class Developer(Employee):
    work_from_home: bool

    def print_developer(self):
        print(f"Developer {self.name} does{'' if self.work_from_home else ' not'} work from home")

def main():
    dev_1 = Developer("Jack", False)
    dev_1.print_developer()

结果:

Developer Jack does not work from home

您还可以将 Developer 对象视为 Employee:

emp_1 = Developer("Jill", True)
emp_1.print_name()

结果:

Jill