子类实例在需要类实例的情况下有效吗?

2024-04-25 07:15:03 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我们有:

class MyClass:
    pass

def my_function(class_instance_argument: MyClass):
    pass

如果我在写一段代码,并且想指出应该传递的对象的类型,我可以这样做。但是,如果我在另一个文件中进一步扩展代码:

class MyClass2(MyClass):
    pass

我不确定子类实例是否是需要类实例的有效数据类型。我知道注释是没有约束力的;事实上,如果我想断言所传递的参数符合我的愿望,我会:

assert(issubclass(type(class_instance_argument), MyClass)))

这对任何子类都适用,即使是有自己的类:

>>> issubclass(type, type)
True

Tags: 对象实例instance代码类型mydeftype
1条回答
网友
1楼 · 发布于 2024-04-25 07:15:03

简单的回答是:不,你什么都不用做。你知道吗

子类型化意味着可替代性。换句话说,如果MyClass2MyClass的一个子类型,那么任何MyClass2都像MyClass一样正常工作。或者,换句话说,您可以在任何需要MyClass的代码中使用MyClass2值,即使该代码从未听说过MyClass2,它也会工作。维基百科有一篇关于Liskov substitution principle的更详细的文章,如果你想了解“正确行事”的真正含义

所以,当您注释这个函数需要MyClass时,这意味着MyClass2是可以接受的,因为MyClass2实际上是MyClass。你知道吗


值得一读的是PEP 484,这是一个添加了类型暗示语法的建议,以及其他从顶部链接的pep。事实上,这个问题就在靠近顶部的Type Declaration Syntax下面:

Expressions whose type is a subtype of a specific argument type are also accepted for that argument.


现在,Python实际上并不强制您的子类成为子类型。它强烈鼓励这样做,但是如果您想编写一个子类,用一个不兼容的签名覆盖方法(甚至将它们隐藏在__getattribute__后面),您可以这样做,而且您将愚弄任何合理的静态类型检查器。你知道吗

但只要你不刻意去愚弄类型检查器,事情就会如你所料。(如果你真的不按你的方式去做……那么,大概你是有理由这么做的,当你明确地强迫他们去做的时候,事情就会起作用。)


Python本身是基于duck类型的思想构建的,不管对象是否是某个类型的实例,只要它非正式地提供了正确的属性和正确的行为,它“像MyClass一样嘎嘎作响”,或者更正式地说它“符合MyClass协议”。你知道吗

您可能认为这不适合静态类型检查。但是,事实证明,效果相当不错。首先,类型提示总是可选的。2但是当你想要显式地检查duck类型的函数时,如果在typing模块中还没有结构协议检查类型,通常有一种非常简单的方法来编写一个结构协议检查类型。例如,您可以不需要list,而需要一个Sequence,它将匹配tuplerange或某个自定义序列类型,只要它符合Sequence的协议,您的库的某个用户发明了一些您从未听说过的序列类型。(在这里,您还可以要求Sequence[int],它将接受listtupleMySillySequence,但前提是类型检查器可以证明它只包含int值。)


1。AFAIK,Python的文档,包括pep集,故意避免引用LSP。LSP是一种描述子类型的松散方式,pep484依赖于一种描述子类型的松散方式。在没有定义“子类型”的情况下使用“子类型树的上界”这样的正式术语已经有点奇怪了,但它非常有效;暗示子类型树实际上是由LSP定义的可能意味着它不太准确。

2。这真的很重要。有些协议很容易使用,但很难定义,而且即使在一个完全注释的程序中,你也可以简单地说Any,这意味着你可以完全注释这个程序,并在其上运行一个类型检查程序(甚至可以查看松散的键入“泄漏”到代码其余部分的位置以及没有泄漏的位置)。

相关问题 更多 >