【问题标题】:Is structural (duck) typing compatible with LSP?结构(鸭子)类型与 LSP 兼容吗?
【发布时间】:2021-06-27 15:44:31
【问题描述】:

在某些情况下,结构子类型是否会导致无法使用 LSP?例如,假设我有一个带有标称类型的 Python* 设置,例如

class Foo(ABC):
    def frobnicate(self) -> int:
        """ frobnicate in a general fashion """

class SubFoo(Foo):
    def frobnicate(self) -> int:
        """ frobnicate in a particular fashion """

def bar(f: SubFoo) -> int:
    return f.frobnicate()

我可以在bar 中确定我有一个SubFoo,并且由于 LSP,我知道调用它会“以一种特定的方式出现故障”。没关系。现在假设我改用结构子类型(注意Protocol

class Foo(Protocol):
    def frobnicate(self) -> int:
        """ frobnicate in a general fashion """

class SubFoo(Foo, Protocol):
    def frobnicate(self) -> int:
        """ frobnicate in a particular fashion """

def bar(f: SubFoo) -> int:
    return f.frobnicate()

我不能确定bar 我有一个SubFoo,因为Foo 也满足该协议,所以我可以,天堂禁止,“以一般方式进行frobnicate”。也就是说,LSP 不适用,因为子类型和超类型之间没有区别。

*我以 Python 为例,因为这就是我所知道的。这是一个与语言无关的问题,但我意识到这可能是由于 Python 的特殊性

【问题讨论】:

  • 你能澄清一下你到底想知道什么吗?一方面,LSP 是关于能够用子类替换父类,或者换句话说,子类在结构上与父类相同。另一方面,协议仅与结构有关,因此SubFoo.frobnicate 的限制完全等同于Foo.frobnicate——两者都不是更通用的方式。
  • @MisterMiyagi 我想知道是否a)在鸭子打字的情况下不能假设LSP或b)我误解了一些东西
  • 是的,我只是在往那个方向输入一个答案。 ;)

标签: python types duck-typing liskov-substitution-principle structural-typing


【解决方案1】:

LSP 是一致性声明,而不是实现。

子类型要求:设 φ(x) 是关于 T 类型的对象 x 的可证明性质。那么 φ(y) 应该对 S 类型的对象 y 为真,其中 S 是 T 的子类型。

请注意,LSP 仅涉及一般的类型和子类型,而不是 nominalstructural 或其他具体的子类型。

释义,可以说“无论一种类型保证什么,它的子类型也必须保证”。由于结构类型与结构有关 - 表示为类型保证 - 这很容易满足。


结构类型根据结构定义子类型。例如,Foo 定义了结构类型:

{frobnicate: (Self) -> int}

值得注意的是,这表示frobnicate 存在,接受Foo 并返回int。它没有说明这是如何发生的,或者输入和输出之间存在什么关系。
重要的是,Foo 并没有说明是一般情况下还是 frobnicate特定的方式。 实现、文档字符串或类似的不是类型的一部分。

同样,SubFoo 定义了 完全相同 结构类型:

{frobnicate: (Self) -> int}

就 LSP 而言,SubFoo <: FooFoo <: SubFoo 的替换都是有效的:FooSubFoo 仅在结构类型中捕获的方式不同,因此不能保证任一种类型。

【讨论】:

    猜你喜欢
    • 2018-10-11
    • 2020-01-10
    • 1970-01-01
    • 1970-01-01
    • 2018-11-18
    • 2011-02-23
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多