简体   繁体   English

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

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

I have this code我有这个代码

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)

This executes just fine, but then I run mypy with mypy foo.py , I get an error that looks like这执行得很好,但后来我用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)

I don't understand what is wrong here and why this type is invalid.我不明白这里有什么问题以及为什么这种类型无效。 What's the way to fix this?解决这个问题的方法是什么?

I'm currently on Python 3.9 with mypy version 0.971.我目前使用 Python 3.9,mypy 版本为 0.971。

Your problem is that mypy does not support dynamic base classes (doesn't matter if they are well-defined).您的问题是mypy不支持动态基类(它们是否定义明确无关紧要)。 See this mypy issue for more workarounds and details.有关更多解决方法和详细信息,请参阅mypy问题

If you're happy enough to have a factory producing class without major modifications, you can just pretend that return type is that class ( try me online! ):如果你很高兴有一家工厂生产 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 is a special constant that is False at runtime and True for type checkers. TYPE_CHECKING是一个特殊常量,在运行时为False ,对于类型检查器为True Here you make type checker think that your FooA is just a type alias (and on py3.10+ or with typing_extensions you can even make it explicit with TypeAlias type annotation).在这里你让类型检查器认为你的FooA只是一个类型别名(在 py3.10+ 或使用typing_extensions你甚至可以使用TypeAlias类型注释使其显式)。

Based on the comments, it appears as if this is a mypy issue.根据评论,这似乎是一个 mypy 问题。 I did find that with Python 3.10 on MAC, the code still required some changes to run correctly:我确实发现在 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

I made two changes:我做了两个改变:

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

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

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