循环导入python

时间:2014-03-15 10:38:58

标签: python python-import circular-dependency

两个文件,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。我很欣赏循环导入是可以避免的,但我需要理解逻辑。

2 个答案:

答案 0 :(得分:3)

Python导入或多或少是

  1. 看看是否已经有一个具有该名称的模块,如果有,立即返回
  2. 模块尚未导入,因此创建模块对象并立即将其放入注册表中,然后加载源并执行它
  3. 如果执行file1会发生什么,执行从主程序开始,然后

    1. file1代码导入file2:因为它不存在所以创建模块对象并开始执行file2
    2. file2代码导入file1:由于file1不存在作为模块,因此创建了一个模块对象并开始执行file1 (作为模块!)
    3. file1代码(作为模块)导入file2:模块已经存在,因此会立即返回部分构造的file2模块对象
    4. file1作为模块完成执行,导入后file2恢复
    5. file2模块完成执行,导入后继续file1 作为主程序
    6. 程序完成
    7. 换句话说,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。