属性错误模块对象没有属性 - 由循环导入引起?

时间:2015-08-05 22:55:59

标签: python-2.7 import

模块OTS

from Tkinter import *
import openTableApiGet

#bunch of code blah blah blah

openTableApiGet.main() # call to the method in the OpenTableApiGet module

模块OpenTableApiGet

import OTS

 class Parser:

#Bunch of code in the class doing stuff


def main(): 
#bunch of code

#The main method the complier says this module 
#doesn't have. Outside of `the Parser class, 
#just hanging out on its  own

为什么会这样?是责任的循环导入我宁愿保留它,但如果我必须改变它,我会。我需要写更多才能让stackoverflow感到高兴,所以我希望你很快就能找到生活中的炸玉米饼!

谢谢大家

1 个答案:

答案 0 :(得分:3)

你是对的,循环导入会使你显示的代码在某些情况下失败。具体来说,如果外部代码首先导入OpenTableApiGet模块,OTS模块在​​尝试调用OpenTableApiGet.main()时将失败。

这就是原因。当Python加载模块时,它从顶部开始并按顺序运行每个语句。当涉及到import语句时,可能必须暂停该模块的执行才能加载另一个模块。

以下是一个例子:

A.py:

print 1
import B
print 3

B.py

print 2

导入A时,这两个简单的将按顺序打印数字1-3。

导入语句并不总是暂停。如果要导入的模块已经加载(或者在循环导入情况下加载的过程中),Python将不再加载它。它将仅引用现有的模块对象并将其放入导入命名空间。

C.py:

print 1
import B
print 3
import B
print 4

运行第二个import语句时不会打印任何内容,因为B模块已经加载(通过第一个import语句)。

以下是模块的简单版本,显示了循环导入的问题:

D.py:

print 1
import E
print 5    # this doesn't get a chance to run, nor the code below
x = 7
print 6

E.py:

print 2
import D
print 3
print D.x    # this causes an exception, since D doesn't have an x attribute yet
print 4

如果您导入D,那么当E中的代码尝试访问D中尚未显示的全局变量时,您将获得1-3打印然后出现异常初始化了。请注意,5在异常之前未打印,因为D的执行暂停,等待E完成加载。

有几种方法可以修复代码。

首先是一个糟糕的修复。如果您先导入E而不是D,则不会出现例外情况(尽管您会得到一些不按顺序打印的数字)。我建议不要依赖它作为解决方案,就像你在以后的代码中更改一些导入一样,它可能会再次破坏并且非常混乱!

通常,“最佳”方法是重新组织代码以消除模块之间的循环依赖关系。将一些代码从一个模块移动到另一个模块或将其分解为可以导入它们的第三个模块。程序员可能非常积极地提倡这种方法,他们使用其他语言学习编程,其中循环依赖总是被打破,但它在Python中并不是一个大问题。

另一个选择是允许循环导入保留,但只是为了避免在模块的顶层做太多的东西。通常,您可以将麻烦的代码放入一个函数(由模块外部的代码调用),尽管循环导入,它仍然可以工作。如果没有任何尝试访问其他模块内容的顶级代码,循环导入不是问题,因为在导入完成并且所有模块都已完全加载之前,实际上并没有多少运行。

以下是一个例子:

F.py:

print 2
import D
print 3
def foo():
    print D.x   # not at top level any more
print 4

main.py

import D, F
F.foo()