[英]Is structural (duck) typing compatible with LSP?
Does structural sub-typing make it impossible to use LSP in some cases?在某些情况下,结构子类型是否会导致无法使用 LSP? For example, say I have a Python* setup with nominal typing like
例如,假设我有一个带有标称类型的 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()
I can be sure in bar
that I have a SubFoo
and because of LSP I know that calling it will "frobnicate in a particular fashion".我可以在
bar
中确定我有一个SubFoo
,并且由于 LSP,我知道调用它会“以特定的方式 frobnicate”。 That's all fine.没关系。 Now suppose I use structural sub-typing instead (note the
Protocol
)现在假设我改用结构子类型(注意
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()
I can't be sure in bar
I have a SubFoo
because a Foo
also satisfies that protocol, and so I may, heaven forbid, "frobnicate in a general fashion".我不能确定在
bar
我有一个SubFoo
因为一个Foo
也满足该协议,所以我可以,天堂禁止,“以一般方式进行 frobnicate”。 That is, LSP doesn't apply because there's no difference between subtypes and supertypes.也就是说,LSP 不适用,因为子类型和超类型之间没有区别。
*I've used Python as an example cos that's what I know. *我以 Python 为例,因为这就是我所知道的。 This is a language agnostic question, but I realise it may be due to Python specifics
这是一个与语言无关的问题,但我意识到这可能是由于 Python 细节
LSP is a statement of consistency, not implementation. LSP 是一致性声明,而不是实现。
Subtype Requirement: Let ϕ(x) be a property provable about objects x of type T. Then ϕ(y) should be true for objects y of type S where S is a subtype of T.
子类型要求:设 φ(x) 是关于 T 类型的对象 x 的可证明性质。那么 φ(y) 对于 S 类型的对象 y 应该为真,其中 S 是 T 的子类型。
Note how LSP is merely about types and subtypes in general – not nominal , structural or other subtypes in specific.请注意,LSP 仅涉及一般的类型和子类型——而不是具体的名义、结构或其他子类型。
Paraphrased, one can say that "whatever a type guarantees, its subtype must guarantee as well".换句话说,可以说“无论一种类型保证什么,它的子类型也必须保证”。 Since structural types are only about structure – expressed as type guarantees – this is trivially satisfied.
由于结构类型仅与结构有关 - 表示为类型保证 - 这很容易满足。
A structural type defines subtyping only in terms of structure.结构类型仅根据结构定义子类型。 For example,
Foo
defines the structural type:例如,
Foo
定义了结构类型:
{frobnicate: (Self) -> int}
Notably, this says that frobnicate
exists, takes a Foo
and returns an int
.值得注意的是,这表示
frobnicate
存在,接受一个Foo
并返回一个int
。 It does not say anything about how that happens, or what relation there is between input and output.它没有说明这是如何发生的,或者输入和 output 之间有什么关系。
Importantly, Foo
does not say whether to frobnicate
in a general or specific fashion.重要的是,
Foo
并没有说是用一般的方式还是特定的方式来frobnicate
。 The implementation, docstring, or similar is not part of the type.实现、文档字符串或类似的不是类型的一部分。
Likewise, SubFoo
defines the exact same structural type:同样,
SubFoo
定义了完全相同的结构类型:
{frobnicate: (Self) -> int}
As far as LSP is concerned, both substitutions SubFoo <: Foo
and Foo <: SubFoo
are valid: Foo
and SubFoo
differ only in ways not captured by structural typing, and thus not guaranteed by either type.就 LSP 而言,
SubFoo <: Foo
和Foo <: SubFoo
两个替换都是有效的: Foo
和SubFoo
的区别仅在于结构类型未捕获的方式,因此任何类型都不能保证。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.