Python 3类型注释和子类

时间:2017-01-22 12:23:37

标签: python python-3.x types

如何引用父类的子类的任何对象'在Python类型注释?

示例:FooBase是一个抽象基类,Foo1Foo2等是子类的子类。我希望函数接受FooBase的任何后代。这样做:

def do_something(self, bar:FooBase):
    pass

或者这只会接受类FooBase的对象,鉴于FooBase是抽象的,这当然是不可能的?在这种情况下,我是否需要构建Union所有案例(请上帝,我希望不是!),还是我可以通过其他方式抽象地表达这种关系?

3 个答案:

答案 0 :(得分:2)

继承也适用于带注释的类型。作为Foo子类型的FooBase的任何实例也是类型FooBase的有效对象。因此,您可以将FooBase对象以及Foo对象传递给函数。

如果您想将该功能仅限于FooBar子类,您可以查看Type[C]构造:The type of class objects

答案 1 :(得分:2)

使用 TypeVar 解决并且 PyCharm 检查器接受它:

from pydantic import BaseModel
class MyModel(BaseModel):
    pass


from typing import TypeVar
BaseModelType = TypeVar('BaseModelType', bound='BaseModel')

async def do_smth(value: BaseModelType):
    pass

# ...

await do_smth(MyModel())

答案 2 :(得分:0)

  

这只会接受类FooBase的对象吗?

不,这也会接受任何子类。这在类型提示PEP理论中也有说明,特别是summary of Gradual Typing section

  

如果t1t2的子类型,则t1类型与类型t2一致。 (但不是相反。)

在处理类型提示时,请查看它以获取更多指示。

  

我是否需要建立所有案例的联盟。

即使你这样做了,也会从Union中删除所有子类,并且会跳过子类。尝试创建您提到的Union

typing.Union[Foo1, Foo2, FooBar]

,结果应为FooBar。它是一个抽象类的事实在这里没有任何区别,Python本身在typing模块中使用了许多抽象类。

Sized abc为例;使用Sized提示函数允许替换任何虚拟子类(定义{{​​1}}的类):

__len__