如何使用Python循环导入 3

How to circular import using Python 3

我想出了一个简单的代码,我无法弄清楚为什么以及如何通过循环导入解决它。

test.py

from test2 import specific_ID

store_name = "testing"
STORE_ID = specific_ID()
print(STORE_ID)

test2.py

from test import store_name

print(store_name)

def specific_ID():
    print("Yay works")
    print(f"Store name: {store_name}")
    return True

我的想法是,当我在 test.py 中有变量 store_name 时,我希望它是一种“常量”值,我可以在其中重新使用 [=] 中的值16=] - 但是它似乎不喜欢它抛出错误的地方:

from test2 import specific_ID
ImportError: cannot import name 'specific_ID' from partially initialized module 'test2' (most likely due to a circular import)

我的问题是,如何重新使用从 test.py 到 test.py 的变量?

应避免循环导入,只需将 test.py 和 test2.py 放在一个包中,并将它们的共享全局变量放在主命名空间中:

__init__.py

STORE_NAME = 'testing'

test.pytest2.py

from . import STORE_NAME

但是你可以一起规避全局变量:

test2.py


def specific_ID(store_name: str) -> int:
    "Return the ID for a store"
    print("Yay works")
    print(f"Store name: {store_name}")
    # lookup id
    return id

test.py

from test2 import specific_ID
    
store_name = "testing"
STORE_ID = specific_ID(store_name)
print(STORE_ID)

当你的函数是纯函数,与全局状态分开时,这使得它们更容易推理和重构。

TLDR:因为在 test2.py 中你只需要引用 store_name 变量,删除 specific_id 的导入和引用 specific_id 的代码,错误应该走开。

长答案:test.py 中的循环导入错误由以下行引起:

from test2 import specific_ID

当python遇到这一行时,它会暂停test.py的执行,并尝试处理test2.py,这样它就可以得到正在执行的项的值已导入,在本例中为 specific_id 函数。

然而,当我们仔细查看 test2.py 时,我们可以看到在文件的顶部,它正试图从 test.py:

导入
from test import store_name

现在,由于我们通过 Python 在 test.py 上暂停执行达到了这一点,这意味着变量 store_name 根本没有被 Python 处理过,因此 test2.py 无法从 test.py 导入它,从而导致循环导入错误。在我看来,文件最好看起来像这样以消除错误:

test.py:

store_name = "testing"

test2.py:

from test import store_name

print(store_name)

def specific_ID():
    print("Yay works")
    print(f"Store name: {store_name}")
    return True

STORE_ID = specific_ID()
print(STORE_ID)

其他两个答案提供了关于如何构建代码以及为什么会出现错误的很好的建议。你应该听他们的,因为他们告诉你做事的正确方法。这个答案与此无关。相反,让我们找出可以使导入真正起作用的最小更改集。

V1

只要 test 定义了 store_name

test2 就会正常导入。您可以通过将 test 中的导入向下移动一行来确保发生这种情况:

store_name = "testing"

from test2 import specific_ID

STORE_ID = specific_ID()
print(STORE_ID)

V2

反之亦然:只要 test2 定义了 specific_IDtest 的导入就可以正常工作。两项更改将允许这样做。一种是在函数定义之后移动导入,因为函数中使用的名称不需要存在,直到你 运行 it:

def specific_ID():
    print("Yay works")
    print(f"Store name: {store_name}")
    return True

from test import store_name

print(store_name)

将导入放在末尾是处理循环导入的“常用”技术。 Common 在引号中,因为问题实际上并不那么普遍,而且一开始就是代码味道。你不应该一开始就这样修复它。

V2b

test2 的第二个选项是在函数内部执行导入。这是一个更重要的变化,因为您还必须去掉 print 语句。考虑到导入的工作方式,除了创建对已加载模块的本地引用之外,导入语句实际上不会做任何事情,因此您不必在每次 运行 函数时都担心昂贵的操作:

def specific_ID():
    from test import store_name

    print("Yay works")
    print(f"Store name: {store_name}")
    return True