繁体   English   中英

如何使用 linter 键入 python class 工厂?

[英]How to type python class factory with linter?

我有这个代码

from abc import ABC
from typing import Type


class AbstractFoo(ABC):
    """Abstract foo."""
    foo_attr: int


def foo_factory(foo_attr_val: int) -> Type[AbstractFoo]:

    class Foo(AbstractFoo):
        foo_attr = foo_attr_val

    return Foo


FooA = foo_factory(5)


class FooB(FooA):
    """Public concrete foo."""

print(FooB.foo_attr)

这执行得很好,但后来我用mypy foo.py运行 mypy,我得到一个看起来像的错误

foo.py:21: error: Variable "foo.FooA" is not valid as a type
foo.py:21: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
foo.py:21: error: Invalid base class "FooA"
Found 2 errors in 1 file (checked 1 source file)

我不明白这里有什么问题以及为什么这种类型无效。 解决这个问题的方法是什么?

我目前使用 Python 3.9,mypy 版本为 0.971。

您的问题是mypy不支持动态基类(它们是否定义明确无关紧要)。 有关更多解决方法和详细信息,请参阅mypy问题

如果你很高兴有一家工厂生产 class 而无需进行重大修改,你可以假装返回类型class( 在线试一下! ):

from abc import ABC
from typing import Type


class AbstractFoo(ABC):
    """Abstract foo."""
    foo_attr: int


def foo_factory(foo_attr_val: int) -> Type[AbstractFoo]:

    class Foo(AbstractFoo):
        foo_attr = foo_attr_val

    return Foo


if TYPE_CHECKING:
    FooA = AbstractFoo
else:
    FooA = foo_factory(5)


class FooB(FooA):
    """Public concrete foo."""

print(FooB.foo_attr)

TYPE_CHECKING是一个特殊常量,在运行时为False ,对于类型检查器为True 在这里你让类型检查器认为你的FooA只是一个类型别名(在 py3.10+ 或使用typing_extensions你甚至可以使用TypeAlias类型注释使其显式)。

根据评论,这似乎是一个 mypy 问题。 我确实发现在 MAC 上使用 Python 3.10,代码仍然需要一些更改才能正确运行:

class AbstractFoo:
    foo_attr: int

def foo_factory(foo_attr: int) -> type[AbstractFoo]:

    class Foo(AbstractFoo):
        AbstractFoo.foo_attr=foo_attr

    return Foo


FooA = foo_factory(5)

class FooB(FooA):
  pass

我做了两个改变:

  1. 类型 -> 类型
  2. foo_attr --> AbstractFoo.foo_attr

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM