不兼容的类型:__main __。TestClass;预期的例子.TestClass;将“自我”传递给另一个模块

时间:2019-06-26 05:25:02

标签: python mypy

背景

我有两个模块。模块1(example)定义了TestClass。模块2(example2)定义函数change_var,该函数接受参数TestClassexample具有方法change,该方法从change_var调用example2并将self作为参数传递。

example2使用TYPE_CHECKING中的typing以确保循环导入不会在运行时出现,但仍允许MYPY检查类型。

change_var中调用change时,MYPY给出错误Argument 1 to "change_var" has incompatible type "__main__.TestClass"; expected "example.TestClass"

Python版本:3.7.3, MYPY版本:0.701

示例代码

example.py

from example2 import change_var


class TestClass:
    def __init__(self) -> None:
        self.test_var = 1

    def change(self) -> None:
        change_var(self)

example2.py

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from example import TestClass


def change_var(obj: "TestClass") -> None:
    obj.test_var = 2

这段代码是我在一个较大的python项目中遇到的实际问题的最小示例。

我希望这样做

这些类型应该匹配(据我所知)相同。

我的直觉是为什么TestClass在调用change_var时尚未完全定义?出于同样的原因,我无法将TestClass本身称为TestClass中的类型,因此无法将TestClass对象传递给需要TestClass对象的函数从课堂本身。对MYPY来说,这不是一个完整的类,因此它使用某种占位符类型。但这只是一种直觉。

问题

  1. 这里到底是什么
  2. 在使MYPY感到满意的同时,实现这种通用代码结构(两个模块,一个类,另一个接受类的函数,对函数的方法调用)的最佳解决方法是什么?

我也愿意完全重构此示例,但我想尝试坚持这种常规结构。

1 个答案:

答案 0 :(得分:1)

这是由于将模块视为脚本(无论是通过-m-c(对于mypy还是--command)而导致的许多破例之一,或简单地python …/module.py)。它仅适用于不关心其创建的类型或功能的身份的琐碎应用程序。 (它们还必须避免对进口和易变的全球状态产生副作用,但无论如何都是好主意。)

除了“不要那样做”之外,解决方案是在软件包中使用__main__.py。即使这样也不是没有问题,因为某些幼稚的递归进口商会像导入一个真正的模块一样将其导入。