循环导入的命名空间

时间:2015-02-21 22:26:20

标签: python python-3.x import namespaces

当shell import模块一个时,我认为一个将导入两个并运行的代码两个所以它会自动导入三个。因此,模块的三个名称都将包含在dir()中。

实际上,当我检查命名空间时,只有模块一个(见下文)。

如何在不包含模块两个三个的命名空间的情况下打印'Hello'?由于one.f1()依赖于两个模块。

>>> ================================ RESTART ================================
>>> import one
in three
In two
in one
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'one']
>>> one.f1()
Hello
>>> 

'one.py'
import two
print('in one')

def f1():
    two.f2()

def f4():
    print ('Hello')

'two.py'
import three
print ('In two')

def f2():
    three.f3()

'three.py'
import one
print('in three')
def f3():
    one.f4()

1 个答案:

答案 0 :(得分:4)

每个模块都有自己的命名空间,包括主脚本。您只将模块one导入主脚本命名空间。

其他模块分别导入模块one和模块two的命名空间。

实际上,仅导入才意味着您在当前命名空间中创建了对导入项(此处为模块对象)的引用。 Python将确保首先加载模块(当您看到正在执行的print()语句时),然后实际导入(当前名称空间中名称的绑定)。

因此,声明import one做了两件事:

  • 查找并加载模块one一次,如果尚未加载。这包括创建模块并在其中插入名称。
  • 将当前名称空间中的名称one绑定到模块。

模块存储在sys.modules;加载开始的那一刻它们就存储在那里。

在您的情况下,加载模块one会触发另一个导入,因此Python会加载模块two以满足该导入。这反过来会触发模块three的导入。 three导入onesys.modules 中已存在的模块。因此,名称one不会出现问题,因为已经存在要绑定的模块。该模块仍然是空的(因为它仍处于加载过程中)。

完整的事件序列是:

  • import one - > sys.modules中没有这样的模块
    • 创建sys.modules['one'],加载代码并开始执行
    • import two - > sys.modules
    • 中没有此类模块
    • 创建sys.modules['two'],加载代码并开始执行
    • import three - > sys.modules中没有这样的模块
      • 创建sys.modules['three'],加载代码并开始执行
      • import one - >存在sys.modules['one'],将one绑定到sys.modules['one']
      • print('in three')
      • 创建函数f3
      • three
      • 的加载完成
    • three绑定到sys.modules['three']
    • print ('In two')
    • 创建函数f2
    • two
    • 的加载完成
    • two绑定到sys.modules['two']
    • print('in one')
    • 创建函数f1f4
    • one
    • 的加载完成
  • 执行one.f1()
    • one.f1()存在且已执行 - > two.f2()
    • two.f2()存在且已执行 - > three.f3()
      • three.f3()存在且已执行 - > one.f4()
      • one.f4()存在并执行> print('Hello')

创建one.f4()时,three.f3()不存在的事实并不重要;只有在执行该函数时才会查找该名称。