【问题标题】:Two Python modules require each other's contents - can that work?两个 Python 模块需要彼此的内容——这行得通吗?
【发布时间】:2012-07-26 18:21:51
【问题描述】:

我有一个带有以下行的 Bottle 网络服务器模块:

from foobar.formtools import auto_process_form_insert

foobar.formtools 模块包含这一行:

from foobar.webserver import redirect, redirect_back

当然,两者都会导致以下错误(分别):

ImportError:无法导入名称 auto_process_form_insert
ImportError: 无法导入名称重定向

这仅仅是一个事实,在 Python 中两个模块不能相互导入并且所有模块导入本质上必须是分层的,还是我做错了什么?或者,是否有没有将所有这些不错的功能放在新模块中的解决方法?

【问题讨论】:

标签: python python-module


【解决方案1】:

模块可以周期性地相互导入,但有一个问题。在简单的情况下,它应该通过将 import 语句移动到文件底部或不使用 from 语法来工作。

这就是为什么有效:

当你导入一个模块时,Python 首先检查sys.modules。如果它在那里,它只是从那里进口。如果它不存在,它会尝试以正常方式导入它;基本上,它会找到文件并运行其中的内容。

运行模块会填充模块的内容。例如,假设我们有这个模块,创造性地命名为example_opener

import webbrowser

def open_example():
    webbrowser.open('http://www.example.com/')

一开始,模块是空的。然后 Python 执行:

import webbrowser

之后,模块只包含webbrowser。然后 Python 执行:

def open_example():
    webbrowser.open('http://www.example.com/')

Python 创建open_example。现在该模块包含webbrowseropen_example

webbrowser 包含此代码:

from example_opener import open_example

def open(url):
    print url

example_opener首先被导入。执行此代码:

import webbrowser

webbrowser还没有被导入,所以Python执行webbrowser的内容:

from example_opener import open_example

example_opener被导入,但尚未完全执行。 Python 不在乎。 Python 将模块从sys.modules 中拉出。此时,example_opener 仍为空。它还没有定义open_example,甚至还没有完成导入webbrowser。 Python在example_opener中找不到open_example,所以失败了。

如果我们从webbrowser 的末尾导入open_example 并从example_opener 的末尾导入webbrowser 会怎样? Python 将从执行以下代码开始:

def open_example():
    webbrowser.open('http://www.example.com/')

webbrowser 尚不存在,但在调用 open_example 之前无关紧要。现在example_opener 只包含open_example。然后执行:

import webbrowser

它还没有被导入,所以 Python 执行webbrowser。它开始了:

def open(url):
    print url

它定义了open。然后执行:

from example_opener import open_example

example_openersys.modules 中,所以它使用它。 example_opener 包含open_example,所以它成功了。 Python 完成导入webbrowser。从example_opener 导入webbrowser 到此结束。这是example_opener 中的最后一件事,所以example_opener 的导入也完成了,也成功了。

【讨论】:

  • 不错的故障。这通常是我在 django 中必须做的,有时你只需要循环导入。在底部或函数或方法范围内导入。
  • @Codemonkey:我注意到您补充说您可以避免使用 from ... import ... 语法,但我已经在顶部的回答中提到了这一点:“在简单的情况下,它应该通过 [. ..] 不使用from 语法。"
【解决方案2】:

不要做from ... import ...。只需执行import ... 并使用模块名称引用其对象。

【讨论】:

  • 我认为这不会解决循环导入问题?
  • @jdi:会的。在导入时,模块将是空的,但由于它还没有尝试获取其中的任何内容(目前),所以没关系。
  • 我想说不特别建议将导入放在底部或始终混合的位置。作为一般经验法则。
  • 这也使可维护性变得更加容易,想象一下有人看到底部的导入,认为在那里很愚蠢,将它们移到顶部并观察您的代码中断。
  • 如果您尝试在导入的第一个模块的模块范围内访问第二个模块的属性,则可能会出现相同的错误。例如,从bar.py 内部说我import foo。我在foo.py 内部import bar。假设foo.py 首先得到处理。 foo -> import bar -> import foo,其中最终的 import foo 将引用部分实例化的 foo 模块。现在,如果在 bar.py 中,在模块范围内,我做了类似 bar_constant = max(100, foo.foo_constant) 的操作,它将失败,因为 bar.py 可以获取句柄的 foo 尚未实例化 foo_constant
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
  • 2023-01-26
  • 2016-09-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多