Python 类型提示:如何判断 X 是 Foo 的子类?

Posted

技术标签:

【中文标题】Python 类型提示:如何判断 X 是 Foo 的子类?【英文标题】:Python type hinting: how to tell X is a subclass for Foo? 【发布时间】:2015-11-19 06:33:24 【问题描述】:

我应该如何为 Python 中的类类型编写类型提示? 考虑这段代码:

class A(object):
    pass

class B(A):
    pass

def register(cls: type[A]):
    assert issubclass(cls, A)

 register(A)
 register(B)

type[A] 是正确的写法吗? 如果我只使用cls: A,这意味着clsA 的一个实例,但我想说cls 是一个类/类型,它至少是A 的子类。

具体来说,我要说明的是参数应该是 一个 Django 模型类型。

【问题讨论】:

This post 讨论这个主题。它可能会有所帮助。 【参考方案1】:

这里的其他当前(2016 年 9 月 22 日)答案似乎不正确。根据 PEP 484(关于类型提示),存在类对象类型的提示,称为 Type[C]。并且根据typing 模块的文档,您可以使用typing.Type[C] 来实现您想要的。我自己在 Python 3.5.2 中使用这些。

引用the PEP:

有时您想谈论类对象,特别是从给定类继承的类对象。这可以拼写为 Type[C] 其中 C 是一个类。澄清一下:虽然 C (用作注释时)指的是类 C 的实例,但 Type[C] 指的是 C 的子类。

并引用the docs:

用 C 注释的变量可以接受 C 类型的值。相反,用 Type[C] 注释的变量可以接受本身就是类的值 - 具体来说,它将接受 C 的类对象。

并参考您的具体示例:

import typing

class A(object):
    pass

class B(A):
    pass

def register(cls: typing.Type[A]):
    assert issubclass(cls, A)

register(A)
register(B)

您可以使用mypy 静态检查此类代码,它应该可以在简单的情况下工作 - 但要注意 mypy 正在进行中,到目前为止,关于 Type[C] 提示存在几个问题。

【讨论】:

多继承呢,可以注释cls必须属于两种类型吗? @laike9m 截至今天,没有:github.com/python/typing/issues/213 - 但它可能有一天会出现在 Python 中。【参考方案2】:

要解决您的一般情况,您必须使用合适的__subclasscheck__ 编写元类。可能,但很麻烦。

在您的 Django 模型类的特定情况下,已经存在显式元类,因此注释应该可以完成工作:

import django.db.model as model

def register(cls: model.base.ModelBase): ...

这会起作用,因为isinstance(models.Model, models.base.ModelBase) 是真的。

【讨论】:

以上是关于Python 类型提示:如何判断 X 是 Foo 的子类?的主要内容,如果未能解决你的问题,请参考以下文章

Python之元类详细解析

反射,元类

PHP:如何修复这种类型提示错误?

父对象的python类型提示字段

python--inspect

Python基础学习代码之变量和类型