问题的一个小背景。我正在用Python2.7编写一个代码,它运行良好。但出于可用性和维护目的,我决定将其分解为模块,这对我来说是新的,因此遇到了一些问题。虽然我已经能够通过点击和试用的方法使它发挥作用,但不确定它是否是正确的方法,因此在这里分享它。这里共享的代码是对真实代码的简化复制,驱动相同的逻辑、顺序和方法。
MainEx.py是在最高级别上运行的脚本
from LogIn_1 import LogIn
global NumTry
NumTry = 2
LogIn()
# xx is here just to show NumTry variable is further used in MainEx script
xx = NumTry*3
基本上,我试图在这里交流的是NumTry变量在MainEx.py(最高级别的脚本)中使用,也在LogIn()函数中使用。并且也将被我正在创建的其他函数使用。
LogIn_1.py是一个用户定义的函数
def LogIn():
from MainEx import NumTry
# following are some computations involving NumTry
print NumTry
运行MainEx.py给出结果:
2
2
问题:1.不确定为什么生成两次结果2.MainEx导入LogIn_1,LogIn_1导入MainEx,这看起来很奇怪。一种乒乓球的情况,从彼此导入变量。
我能够通过以下改变来纠正结果:主要示例
from LogIn_1 import LogIn
global NumTry
NumTry = 2
#LogIn()
# xx is here just to show NumTry variable is further used in MainEx script
xx = NumTry*3
LogIn_1.py
def LogIn():
from MainEx import NumTry
# following are some computations involving NumTry
print NumTry
LogIn()
运行MainEx.py给出结果:
2
我正在努力了解最佳实践,以避免未来出现问题。
如果你在代码中添加了一堆打印语句,你可以遵循血腥的细节:
# MainEx.py
print 'MainEx: start'
from LogIn_1 import LogIn
print 'MainEx: after Login import'
global NumTry
NumTry = 2
print 'MainEx: before Login() call'
LogIn()
print 'MainEx: after Login() call'
xx = NumTry*3
print 'MainEx: finish'
# LogIn_1.py
print 'start LogIn_1'
def LogIn():
print ' Login(): start'
from MainEx import NumTry
print ' Login(): after MainEx import'
print NumTry
print ' Login(): finish'
print 'finish LogIn_1'
输出:
MainEx: start
start LogIn_1
finish LogIn_1
MainEx: after Login import
MainEx: before Login() call
Login(): start
MainEx: start # Code in MainEx running again!
MainEx: after Login import
MainEx: before Login() call
Login(): start
Login(): after MainEx import
2
Login(): finish
MainEx: after Login() call
MainEx: finish
Login(): after MainEx import
2
Login(): finish
MainEx: after Login() call
MainEx: finish
正如您所看到的,将(a)循环导入与(b)具有顶级副作用的代码相结合会导致不正常的结果。特别是,当from MainEx import NumTry
在Login()
调用中运行时,Python似乎必须重新执行MainEx
中的代码,因为该模块还没有NumTry
属性,导致双重打印。我真的没想到会有这样的结果。。。但它就在那里。
最佳实践建议:
将导入语句放在模块的顶部,而不是函数或类内部。
设计代码以避免循环导入。你的程序的模块最终有一种层次结构:你的低级别模块从你自己的代码库中什么都不导入;并且您的高级模块导入您的低级模块。
设计您的模块,使其顶层不会发生。。模块只应定义类、定义函数、分配常量或导入较低级别的模块。只有您的系统的主模块应该做一些事情——并且应该调用您的顶级函数(传入任何命令行参数),甚至该调用也应该是有条件的,如下所示:
import sys def main(args): ... def foo(): ... def bar(): ... if __name__ == '__main__': main(sys.argv[1:])