【问题标题】:Python 3 type annotations and subclassesPython 3 类型注解和子类
【发布时间】:2017-06-07 01:08:27
【问题描述】:

如何在 Python 类型注解中引用“任何继承父类的对象”?

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

def do_something(self, bar:FooBase):
    pass

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

【问题讨论】:

    标签: python python-3.x types


    【解决方案1】:

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

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

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

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

    我需要建立一个所有情况的联合吗?

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

    typing.Union[Foo1, Foo2, FooBar]
    

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

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

    def foo(obj: Sized): pass
    
    foo([1, 2, 3, 4]) # ok
    foo([2, 3, 4, 5]) # ok
    

    【讨论】:

      【解决方案2】:

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

      如果您想将函数限制为只有FooBar子类,您可以查看Type[C] 构造:The type of class objects

      【讨论】:

        【解决方案3】:

        使用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())
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-12-06
          • 2016-12-11
          • 1970-01-01
          • 1970-01-01
          • 2016-08-16
          • 2021-09-29
          • 2010-11-19
          相关资源
          最近更新 更多