2012-11-18 303 views
2

首先,这很可能不是路径问题。无法导入模块

我在eclipse中有一个pydev项目。下面是目录结构:

Genetic-Framework 
    | Genetic-Framework 
    | Genetic 
     | __init__.py 
     | GA.py 
     | crossover.py 
     | fitness.py 
     | individual.py 
     | mutation.py 
     | population.py 
     | selection.py 
     | settings.py 
     | visualization.py 

GA.py,我有以下行:

from Genetic import settings, selection, visualization as vis 

是的,Geneticsys.path。不过,我得到以下错误:

File "/.../Genetic-Framework/Genetic-Framework/Genetic/GA.py", line 17, in <module> 
    from Genetic import settings, selection, visualization as vis 
ImportError: cannot import name settings 

然而,当我从那条线,一切进口就好删除settings

有趣的是,settings.py第一线中是这样的:

from Genetic import fitness, selection, mutation, crossover, population, GA 

;当我从该行删除GA,一切似乎都导入就好了。

为什么我会收到此错误?这是循环进口的一些问题吗?我怎样才能解决这个问题?

+2

你需要有一个'__init __。py'文件才能工作。你的路上有一个名为'Genetic.py'的文件吗?它可能不会导入您认为正在导入的内容。 – BrenBarn

+0

There/is/an __init __。py'我把它从我的文章中的dir列表中排除了,因为我认为它是不相关的。发布编辑 – inspectorG4dget

回答

4

是的,这是循环进口的问题。

问题

的问题是,当运行GA.py,它首先尝试导入settings。这意味着settings.py开始运行,并立即尝试导入GA

然而,GA已经在装载过程中,所以GA.py没有得到第二次运行 - 相反,settings只是用来加载GA已在内存(这是目前大部分是空的,因为它仍在执行它的进口)。

因此,事情settings尝试使用出来的东西GA失败,是因为他们正在寻找GA的事情尚未确定(因为GA.py处理已没有得到过去的进口还)。

这使得settings.py的评估引发异常,这表现为导入失败(因为在导入期间引发的异常导致导入失败)。

解决方案

a)首先避免这种情况。

一般来说,您应该尽量避免循环导入。它们通常意味着你有非常奇怪的依赖性结构,以后很难调试。

这样做的一种方法是尝试找到两个模块中都需要的东西,并将它们分解为另一个可以在另外两个模块之间共享的单独的第三个模块 - 因此不是在B中使用Ax,而是使用By A,你在A和B中使用Cx和Cy。

b)在加载所有内容之前,不要尝试从循环导入中使用事物。

你可以做的另一件事是推迟使用从另一个模块的东西,直到所有的导入完成。换句话说,不要尝试从顶级代码引用导入模块的内容,而是在所有导入完成后,将其放入类初始化程序或稍后可调用的函数中。

例如,而不是此...

import Foo 

class Baz: 
    top_level_variable = Foo.bar 

,你可以这样做:

import Foo 

class Baz: 
    def __init__(self): 
     self.instance_variable = Foo.bar 

显然,实例属性是从类属性略有不同,但这个想法是实际推迟在所有模块完成执行之后,必须从其他模块中查找事件,并从而获得其内容。还要注意from Foo import bar在这里会失败,因为它在导入时试图访问Foo的内容,这是需要避免的。

+0

你做得很好,直到你到了选项b,根本不工作。当你引用一个模块的内容时,Python并不关心:导入它的这一事实意味着它必须被解析,这导致了循环依赖。然而,将* import *移入'__init__'函数是一个潜在的解决方案。 –

+1

@DanielRoseman:的确,模块必须被解析,但这并不意味着所有的对象都必须完全可用。你对'from ... import ...'说的是真实的,但是当你使用一个简单的'import foo'时,只要导入的模块可以被正确地解析,你可以远离循环导入,只要你不会尝试访问变量,直到模块加载完成后,它会没事的。关键的是,在上面B的第二个例子中,访问'Foo.bar'的代码不会在模块导入时执行。 – BrenBarn

+0

@BrenBarn钉了它。当导入发生时,不会发生该问题,但当导入模块尝试*在导入的模块中访问*某些内容时。如果你可以避免这样的访问(这必然包括避免'from ... import ...'格式导入),那么它将起作用。 – Amber