【问题标题】:Do all dynamic languages have the circular import issue?所有动态语言都有循环导入问题吗?
【发布时间】:2011-01-18 02:29:05
【问题描述】:

对于以下 Python 代码:

first.py

# first.py
from second import Second

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

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 个模型相互依赖。我知道可能的解决方案是重新设计项目或按需导入。我只是想知道其他动态语言的开发者是否遇到过这个问题。

【问题讨论】:

  • 你应该总是继承 object 而不是什么都没有,这样你就可以使用新风格的类了。
  • @Mike,他没有指定他的 Python 版本。
  • @Hamish Grubijan,i)他使用了 Python 3 中没有的 print 语句,ii)他说他使用的是不支持 Python 3 的 Django,以及 iii)没有人使用蟒蛇3; Python 2 是合理的默认假设。

标签: python ruby dynamic-languages


【解决方案1】:

请注意,如果您只是将导入移动到模块的末尾,循环导入将按预期工作。像这样:

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 值得一读。不过,正如其他人所建议的那样,您最好重新调整代码以避免完全循环导入。

【讨论】:

    【解决方案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 允许使用字符串定义键以在必要的情况下提供帮助。如果你真的需要在另一个类中实例化这两个类,你就会遇到更大的问题。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 这可能是个坏主意,但让两个模块相互依赖并不是一个悖论。
      • 可能会逐渐地相互依赖,但明显如 OP 中所建议的那样?悖论。
      • 不,不是。你没听说过递归吗?
      • 绝对是递归函数。递归模块?从不。
      • 如果不同文件中的两个函数相互递归调用,就会出现这个问题。解决方案是从另一个内部导入一个。仅仅因为两个函数在不同的文件中,并不意味着它们在不同的模块中。这只是意味着它们在某种程度上在逻辑上是分开的,或者因为将它们组合起来会产生一个太大的文件。
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

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

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

          • 那么如果我想将数千行代码拆分成多个文件,这是一个设计问题?
          • 当您将代码从一个文件拆分为多个依赖循环导入的文件时,您还没有使用最佳设计。
          猜你喜欢
          • 1970-01-01
          • 2013-05-24
          • 1970-01-01
          • 2020-03-09
          • 2011-02-04
          • 1970-01-01
          • 2018-07-01
          • 2023-03-17
          • 2015-05-23
          相关资源
          最近更新 更多