创建或 isinstance 检查其类型参数的 Python 泛型

lor*_*org 2 python generics typing

我想创建一个可以用类型参数化的可继承类。这是一个没有类型注释的工作示例:

class Simple:
    pass

class Bla:
    obj_class = Simple

    def do(self):
        return self.obj_class()

    def check(self, x):
        return isinstance(x, self.obj_class)
Run Code Online (Sandbox Code Playgroud)

此代码的用户将从 Bla 继承,并可以设置不同的 obj_class,如下所示:

class Advanced(Simple):
    pass

class Foo(Bla):
    obj_class = Advanced
Run Code Online (Sandbox Code Playgroud)

当我想正确输入注释时,问题就开始了。我想让 Bla 继承自 Generic[T],其中 T 定义为TypeVar('T', bound=Simple),但是构造函数 T() 和 isinstance 将不起作用,并且手动将不同的类分配给 obj_class 也不起作用。

这是一个非工作示例,因为 T 不能用于非键入上下文:

class Simple:
    pass

T = TypeVar('T', bound=Simple)

class Bla(Generic[T]):
    def do(self) -> T:
        return T()

    def check(self, x: Any) -> bool:
        return isinstance(x, T)
Run Code Online (Sandbox Code Playgroud)

这是另一个非工作示例,由于类型不兼容,我无法将 Simple 分配给 obj_class。

class Simple:
    pass

T = TypeVar('T', bound=Simple)

class Bla(Generic[T]):
    obj_class: Type[T] = Simple

    def do(self) -> T:
        return self.obj_class()

    def check(self, x: Any) -> bool:
        return isinstance(x, self.obj_class)

class Advanced(Simple):
    pass

class Foo(Bla):
    obj_class = Advanced
Run Code Online (Sandbox Code Playgroud)

有没有办法解决这个问题?

小智 6

你不需要Type[T] = Simple.

mypy 说:

赋值中的类型不兼容(表达式的类型为“Type[Simple]”,变量的类型为“Type[T]”)。

您正在尝试将具体类型分配给泛型类型变量。

相反,请执行以下操作:

class Simple:
    pass


class Advanced(Simple):
    pass


class Other:
    pass


T = TypeVar('T', bound=Simple)


class Bla(Generic[T]):
    obj_class: Type[T]

    def do(self) -> T:
        return self.obj_class()

    def check(self, x: Any) -> bool:
        return isinstance(x, self.obj_class)


class SimpleFoo(Bla[Simple]):
    obj_class = Simple


class AdvancedFoo(Bla[Advanced]):
    obj_class = Advanced


class OtherFoo(Bla[Other]):
    obj_class = Other
Run Code Online (Sandbox Code Playgroud)

现在,mypy 正确说明:

错误:“Bla”的类型参数“tmp.Other”必须是“tmp.Simple”的子类型

笔记

OtherFoo必须Bla使用特定类型进行子类化,因此 mypy 会正确警告您。

以下不会产生错误:

class OtherFoo(Bla):
    obj_class = Other
Run Code Online (Sandbox Code Playgroud)