5

对于以下 Python 代码:

第一个.py

# first.py
from second import Second

class First:
    def __init__(self):
        print 'Second'

第二个.py

# second.py
from first import First

class Second:
    def __init__(self):
        print 'Second'

创建文件并从 shell 运行以下命令后:

python first.py

我得到错误:ImportError: cannot import name Second

像 Ruby 这样的其他动态语言有这种问题吗?我问的原因是因为我在 Django 项目中遇到了这个问题,其中 2 个模型相互依赖。我知道可能的解决方案是重新设计项目或按需导入。我只想知道其他动态语言的开发人员是否遇到过这个问题。

4

6 回答 6

12

Python 可以在一定程度上处理循环导入。在没有意义的情况下,该解决方案可能在另一种语言中仍然没有意义。大多数问题可以通过使用import first和稍后引用来解决,first.First而不是from first import First

如果您可以将共享代码移到它自己的模块中,或者以某种方式重构循环导入的需要,那就更好了。循环导入总是表明存在设计问题。

于 2010-02-17T22:48:05.947 回答
3

递归定义不是仅限于动态语言的问题。这也是静态类型语言中的一个问题。它可能显示为编译错误,因为其中一种类型将在定义之前使用。

在某些语言中,解决方案是使用前向声明。其他语言通过一次编译多个文件来解决这个问题。

在 Python 中,您可以通过将导入从顶层移动到需要它们的函数中来解决问题。此外,循环引用实际上并不是错误,所以如果你小心的话,无论如何你都可以让它工作。

于 2010-02-17T22:48:13.077 回答
2

所有其他海报都是正确的,循环导入是一个您应该在结构上解决的严重问题。

但是,特别是对于 Python/Django 模型,您可以使用字符串名称来设置外键以避免这些循环依赖问题——

#appA/models.py
class A(models.Model):
  b = models.ForeignKey('appB.b')

#appB/models.py
class B(models.Model):
  a = models.ForeignKey('appA.a')

数据库表中的循环引用不一定是坏事(但并不总是好事);Django 允许使用字符串定义键以在必要的情况下提供帮助。如果你真的需要在另一个类中实例化这两个类,你就会遇到更大的问题。

于 2010-02-17T22:57:00.517 回答
1

Note that if you just move your imports to the end of your module, circular imports will work as expected. Like so:

first.py

# first.py
class First:
  def __init__(self):
    print 'Second'
from second import Second

second.py

# second.py
class Second:
    def __init__(self):
        print 'Second'
from first import First

Fredrik Lundh's import reference is worth a read. As others have advised, though, you're best off rejiggering your code to avoid circular imports entirely.

于 2010-02-18T01:18:53.653 回答
1

从逻辑上讲,这是一个悖论。这是代码形式的先有鸡还是先有蛋的问题。其中一个必须先来。按照其他人的建议,请回到绘图板上,从长远来看,您会做得更好。语言阻止你做这些事情是有原因的!

于 2010-02-17T22:52:05.297 回答
-1

这不是与“动态”语言相关的问题。这是一个架构问题。您需要更好地了解您是如何构建事物的。

于 2010-02-17T22:49:03.567 回答