小编典典

没有循环导入的 Python 类型提示

all

我正试图将我的大班分成两部分;好吧,基本上进入“主”类和带有附加功能的mixin,如下所示:

main.py文件:

import mymixin.py

class Main(object, MyMixin):
    def func1(self, xxx):
        ...

mymixin.py文件:

class MyMixin(object):
    def func2(self: Main, xxx):  # <--- note the type hint
        ...

现在,虽然这工作得很好,但类型提示MyMixin.func2当然不能工作。我不能 import
main.py,因为我会得到一个循环导入并且没有提示,我的编辑器(PyCharm)无法分辨是什么self

我正在使用 Python 3.4,但如果那里有可用的解决方案,我愿意迁移到 3.5。

有什么方法可以将我的类拆分为两个文件并保留所有“连接”,以便我的 IDE 仍然为我提供自动完成功能以及它所带来的所有其他好东西都知道类型?


阅读 82

收藏
2022-05-30

共1个答案

小编典典

恐怕没有一种非常优雅的方式来处理一般的导入周期。您的选择是重新设计代码以删除循环依赖,或者如果不可行,请执行以下操作:

# some_file.py

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from main import Main

class MyObject(object):
    def func2(self, some_param: 'Main'):
        ...

TYPE_CHECKING常量始终False在运行时,因此不会评估导入,但 mypy(和其他类型检查工具)将评估该块的内容。

我们还需要将Main类型注释变成一个字符串,有效地向前声明它,因为该Main符号在运行时不可用。

如果您使用的是 Python 3.7+,我们至少可以通过利用PEP
563
跳过提供显式字符串注释:

# some_file.py

from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from main import Main

class MyObject(object):
    # Hooray, cleaner annotations!
    def func2(self, some_param: Main):
        ...

from __future__ import annotations导入将使所有类型提示成为字符串并跳过评估它们
这可以帮助我们的代码稍微更符合人体工程学。

综上所述,在 mypy 中使用 mixins
可能需要比目前更多的结构。Mypy推荐了一种基本上deceze描述的方法——创建一个你MainMyMixin类都继承的
ABC。如果您最终需要做类似的事情来让 Pycharm 的检查器满意,我不会感到惊讶。

2022-05-30