你有一个circular import
当您在 Python 中导入模块时,例如,import __main__(如您的示例中所示),会为模块的命名空间创建一个 module 对象,该命名空间最初为空。然后,随着模块主体中的代码被执行——分配的变量、定义的函数和类等,命名空间被按顺序填充。例如。采取以下脚本:
$ cat a.py
print(locals())
an_int = 1
print("after an_int = 1")
print(locals())
def a_func(): pass
print("after def a_func(): pass")
print(locals())
然后运行它:
$ python a.py
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__file__': 'a.py', '__doc__': None, '__package__': None}
after an_int = 1
{'an_int': 1, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'a.py', '__package__': None, '__name__': '__main__', '__doc__': None}
after def a_func(): pass
{'an_int': 1, 'a_func': <function a_func at 0x6ffffeed758>, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'a.py', '__package__': None, '__name__': '__main__', '__doc__': None}
您可以看到命名空间被逐行填充。
现在说我们修改它:
$ cat a.py
print(locals())
an_int = 1
print("after an_int = 1")
print(locals())
import b
print("after import b")
def a_func(): pass
print("after def a_func(): pass")
print(locals())
并添加b.py:
$ cat b.py
import sys
print('a is in progress of being imported:', sys.modules['a'])
print("is a_func defined in a? `'a_func' in sys.modules['a'].__dict__`:",
'a_func' in sys.modules['a'].__dict__)
from a import a_func
然后像这样运行它:
python -c 'import a'
你会得到一些以 Traceback 结尾的输出:
...
after an_int = 1
{'an_int': 1, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'a.py', '__package__': None, '__name__': '__main__', '__doc__': None}
a is in progress of being imported: <module 'a' from '/path/to/a.py'>
is a_func defined in a? `'a_func' in sys.modules['a'].__dict__`: False
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "a.py", line 7, in <module>
import b
File "b.py", line 1, in <module>
from a import a_func
ImportError: cannot import name 'a_func'
如果您将import b 移动到a_func 的定义之后:
$ cat a.py
print(locals())
an_int = 1
print("after an_int = 1")
print(locals())
def a_func(): pass
print("after def a_func(): pass")
print(locals())
import b
print("after import b")
再次运行python -c 'import a',你会看到它工作正常,输出以“after import b”结尾。
奖励问题:为什么我运行python -c 'import a' 而不仅仅是python a.py?如果您尝试后者,之前的版本实际上会工作,并且会出现两次导入a.py。这是因为当您运行python somemodule.py 时,它最初不是作为somemodule 导入的,而是作为__main__ 导入的。所以从导入系统的角度来看,a 模块在运行from a import a_func 时还没有被导入。一个非常令人困惑的警告。
所以如果你有类似__main__.py的东西:
import config
address = 1
在config.py:
from __main__ import address
当您运行python __main__.py 时,当它运行import config 时,address 尚未分配,因此config 中尝试从__main__ 导入address 的代码导致@ 987654353@.
在您的情况下,它有点复杂,因为您没有直接在 __main__ 中导入 config,但间接情况仍然如此。
在这种情况下,您不应该通过 import 语句在模块之间传递变量。事实上,__main__ 应该只是您代码的命令行前端,而您的其余代码应该能够独立于它工作(例如,一个好的设计将允许您运行 from tests.test_runner import runner 并调用runner() 原则上来自交互式 Python 提示符,即使您从未真正以这种方式使用它。
所以改为让runner(...) 为它需要的任何选项提供参数。然后__main__.py 只会从命令行参数中获取这些参数。例如:
def runner(address=None):
# Or maybe just runner(address) if you don't want to make the
# address argument optional
然后
if __name__ == '__main__':
address = sys.argv[1] # Use argparse instead if you can
runner(address=address)