所有动态语言都有循环导入问题吗?
对于以下的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'
在创建了这些文件后,我在命令行中运行了以下内容:
python first.py
结果我遇到了这个错误:ImportError: cannot import name Second
像Ruby这样的其他动态语言也会有这种问题吗?我之所以问这个,是因为我在一个Django项目中遇到了这个问题,里面有两个模型相互依赖。我知道可能的解决办法是重新设计项目或者按需导入。我只是想知道其他动态语言的开发者是否也遇到过这个问题。
5 个回答
其他所有发帖者都说得对,循环导入是个严重的问题,你应该从结构上去解决它。
不过,特别是在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允许用字符串来定义键,这在必要的时候会很有帮助。如果你真的需要在两个类之间互相实例化,那你可能还有更大的问题需要解决。
递归定义的问题不仅仅出现在动态语言中,静态类型语言也常常会遇到这个问题。它可能会导致编译错误,因为某个类型在定义之前就被使用了。
在某些语言中,解决这个问题的方法是使用前向声明。其他语言则通过同时编译多个文件来解决这个问题。
在Python中,你可以通过把导入语句从最上面的位置移动到需要它们的函数内部来解决这个问题。此外,循环引用其实并不是错误,所以如果你小心一点,还是可以让它正常工作。
Python在一定程度上可以处理循环导入的问题。对于那些无法理解的情况,解决方案在其他语言中可能也没有意义。大部分问题可以通过先使用 import first
,然后再用 first.First
来引用,而不是用 from first import First
来解决。
如果能把共享的代码放到一个单独的模块里,或者以某种方式重构代码,避免循环导入,那会更好。循环导入总是说明设计上存在问题。