Python __import__函数中的`globals`和`locals`参数是用来干什么的?

11

Python文档中有一部分是关于 __import__ 的,我不太理解:

__import__(name[, globals[, locals[, fromlist[, level]]]])

该函数导入模块 name,可能使用给定的 globalslocals 来确定如何在包上下文中解释 name。标准实现根本不使用它的 locals 参数,并仅使用其 globals 来确定导入语句的包上下文。

关于模块名称有哪些需要“解释”的内容呢?什么是包上下文?

一个使用这些参数的示例调用如下:

spam = __import__('spam', globals(), locals(), [], -1)
为什么示例提供了globals()locals()给函数?如果我只提供globals()会发生什么?或者两个都不提供呢? 我可能忽略了与导入模块相关的命名空间逻辑的某些部分。您能否指向一篇解释此事/具有__import__函数示例的文章?

1
这个问题不应该移动到StackOverflow吗? - Eric O. Lebigot
这很有趣,我开始在SO上写这篇文章,但是我在思考是否应该将其发布到programmers.SE上... 我显然需要查看FAQ... - Martin Tóth
你应该从以下答案中选择一个作为这个问题的被接受的答案。在我看来,9000的回答非常准确地解释了Python如何使用“globals”来确定模块命名空间。 - Kumba
3个回答

6
标准实现根本不使用它的`locals`参数,并且仅使用其`globals`参数来确定`import`语句的包上下文。 (来源于docs.python.org) 我仍然不知道`globals`如何使用; 有哪个全局变量会影响`import`语句的工作方式吗? 编辑:在Python 2.5源代码中查看`import.c`后,我发现`__import__`期望在`globals`中找到`__name__`或`__path__`之一,以便相对于这些变量中找到的路径增加导入搜索路径,按顺序进行。

谈到晦涩难懂的问题。基本上,不需要传递包含所有全局变量的大块内存(假设Python不是通过引用来实现的),而是可以简单地传递一个字典,其中只有一个键“__name__”,将其设置为调用模块的__name__属性,Python 将与之一起工作。Python文档应该更新这个小贴士的信息。 - Kumba
@Kumba:假设Python几乎所有操作都是通过引用完成的,除了一些原始数字操作。字典绝对是按引用传递的。Python 3.3甚至引入了一种实现共享键的字典,也就是说,键也是通过引用访问的。如果你想抱怨的话,可以谈谈缓存一致性 :) - 9000
由于曾经在非缓存一致硬件上玩过(并拥有),我只能开始想象那场噩梦。值得庆幸的是(或者可悲的是,你可以自己选择),我编写的 Python 代码至少要运行在 Python 2.4 上。我避免使用 3.x,因为我知道它彻底颠覆了语言,我的很多代码可能需要进行严重的重写才能工作。 - Kumba

3

globals用于确定导入调用的当前上下文。例如:

"""
/myproject/a/b.py
/myproject/a/foo.py
/myproject/c/d.py
/myproject/c/foo.py
"""

# Which foo gets imported?

import foo #1
foo = __import__('foo') #2

它们并不相同,因为在#2上没有(简单的)方法可以知道从哪个模块调用了导入。__import__函数需要知道当前模块是哪一个才能正确地导入foo
__import__()内部,使用globals来获取调用导入的当前模块的引用。从__import__ 源代码中:

返回正在执行导入操作的包。如果globals来自模块foo.bar.bat(本身不是包),则返回foo.bar的sys.modules条目。如果globals来自包的init.py,则返回sys.modules中的该包条目,作为借用的引用。


假设在b.pyd.py中都有import foo,那么Python如何知道要导入哪一个?对于b.py,为什么它会在../c中寻找foo - Martin Tóth
如果在/myproject/e.py文件中有import foo,那么它不应该工作。应该使用import a.fooimport c.foo。抱歉,我似乎无法提供“引起麻烦”的示例,你能给我一个提示吗? - Martin Tóth

-2
“模块名称”有什么需要“解释”的?“包上下文”是什么?
当您输入时,
>>> a

Python必须“解释”该名称。它是全局的吗?还是本地的?

>>> def f(x):
...    return x * a

现在,x 明显是本地的。 a 必须被“解释”。全局的?本地的?

为什么示例提供globals()和locals()给函数?如果我只提供globals()会发生什么?或者两个都不提供呢?

试一下就知道了。真的。玩弄它比询问更容易。
重要的是,在>>>提示处执行的操作是全局的。
您需要定义函数以创建本地上下文,以便您可以看到全局和本地之间的差异。

有点悲催但也挺有趣的事实是,被导入的模块会忽略导入它的模块中几乎所有的全局变量,而 __import__ 函数则完全忽略 locals 参数。除此之外,你说得没错 :) - 9000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接