两个文件,file1.py,file2.py。有人可以解释为什么第1.8行会打印垃圾邮件== 1而不是垃圾邮件== 2?我已阅读所有python循环导入帖子,但我仍然不明白这一点。另外,我不明白为什么从file2导入时会再次从头开始解释file1。我印象中的模块一旦导入一次就不会再次加载。
# file1.py
print('1.1: initializing spam to 0')
spam = 0
spam += 1
print('1.4: spam == {}'.format(spam))
print('1.5: importing file2')
import file2
print('1.7: imported file2')
print('1.8: spam == {}'.format(spam)) # why 1 and not 2?
print('FILE 1 PARSED') # why is this executed twice?
# file2.py
print('\t\t\t2.1: importing file1')
import file1
print('\t\t\t2.3: imported file1, file1.spam == {}'.format(file1.spam))
file1.spam += 1
import file1
print('\t\t\t2.6: print from file2: file1.spam == {}'.format(file1.spam))
print('\t\t\tFILE 2 PARSED')
我得到的输出是:
1.1: initializing spam to 0
1.4: spam == 1
1.5: importing file2
2.1: importing file1
1.1: initializing spam to 0
1.4: spam == 1
1.5: importing file2
1.7: imported file2
1.8: spam == 1
FILE 1 PARSED
2.3: imported file1, file1.spam == 1
2.6: print from file2: file1.spam == 2
FILE 2 PARSED
1.7: imported file2
1.8: spam == 1
FILE 1 PARSED
PS。我很欣赏循环导入是可以避免的,但我需要理解逻辑。
答案 0 :(得分:3)
Python导入或多或少是
如果执行file1
会发生什么,执行从主程序开始,然后
file1
代码导入file2
:因为它不存在所以创建模块对象并开始执行file2
file2
代码导入file1
:由于file1
不存在作为模块,因此创建了一个模块对象并开始执行file1
(作为模块!)file1
代码(作为模块)导入file2
:模块已经存在,因此会立即返回部分构造的file2
模块对象file1
作为模块完成执行,导入后file2
恢复file2
模块完成执行,导入后继续file1
作为主程序 换句话说,spam
会有两个实例:一个在"主程序"内。 file1.py和模块中的一个 file1
。
考虑这个简化的测试用例:
# p1.py
import p2, sys
p1d = {}
print id(p1d), id(sys.modules['p1'].p1d)
# p2.py
import p1
print "HERE"
运行p1.py
您将获得类似
18465168 18465168
HERE
17940640 18465168
前两个数字相等,因为print
是从p1
模块执行的,而后两个数字是不同的,因为print
是从p1
执行的{1}} 主程序,这是一个不同的实例。
PS:如果你故意编写了这样做的代码(即间接导入自己的另一个实例作为模块的主要代码),你应该被投入监狱: - )
答案 1 :(得分:0)
当file1.py
作为主脚本运行时,它不是file1
模块。它是__main__
模块。假装它是一个完全独立的文件,看起来与file1
模块完全相同,因为这就是Python对待它的方式。
Python将file1.py
作为__main__
运行,导入file2
,导入file1
。由于__main__
模块与file1
模块不同,file1.py
会再次运行。
当file1
导入file2
时,由于file2
已被导入,file1
将获取半构造的file2
模块对象并继续运行。它不会为file2
提供增加file1.spam
的机会。这就是第1.8行第一个实例打印1的原因。
当执行回到file2
时,它会增加file1.spam
,因此第2.6行打印2.但是,__main__.spam
仍为1.这就是执行返回{{1第1.8行的第二个实例也打印1。