61

我有两种特定情况,我不明白 Python 中的导入是如何工作的:

第一种具体情况:

当我在两个不同的 Python 脚本中导入同一个模块时,该模块不会被导入两次,对吧?Python第一次遇到它是导入的,第二次是检查模块是否已经导入,还是做一个副本?

第二种具体情况:

考虑以下模块,称为bla.py

a = 10

然后,我们有foo.py一个导入的模块bla.py

from bla import *

def Stuff ():
    return a

之后,我们有一个名为 的脚本bar.py,由用户执行:

from foo import *
Stuff() #This should return 10 
a = 5
Stuff()

这里我不知道:Stuff()返回 10 还是 5?

4

2 回答 2

73

第1部分

该模块仅加载一次,因此再次导入不会造成性能损失。如果您确实希望再次加载/解析它,则必须使用reload()该模块。

首先检查的是sys.modules,之前已经导入的所有模块的缓存。[来源]


第2部分

from foo import *导入a到本地范围。给 赋值时a,它会被新值替换 - 但foo.a不会触及原始变量。

因此,除非您import foo和 modify foo.a,否则两个调用都将返回相同的值。

对于诸如 list 或 dict 之类的可变类型,它会有所不同,修改它确实会影响原始变量 - 但为其分配新值仍然不会 modify foo.whatever

如果您想了解更多详细信息,请查看http://docs.python.org/reference/executionmodel.html

以下构造绑定名称:函数的形式参数、导入语句、类和函数定义(这些在定义块中绑定类或函数名称),以及如果出现在赋值中作为标识符的目标,for循环头,在第二个except 子句标题的位置或在 with 语句中的后面。

两个粗体部分与您相关:首先,名称在导入期间a绑定到 的值。foo.a然后,在做a = 5的时候,名字a是绑定的5。由于修改列表/字典不会导致任何绑定,因此这些操作将修改原始操作(bfoo.b绑定到您操作的同一对象)。将新对象分配给b将再次成为绑定操作,因此bfoo.b.

还值得注意的是该import语句的确切作用:

  • import foo将模块名称绑定到当前范围内的模块对象,因此如果您修改foo.whatever,您将使用该模块中的名称 - 任何修改/分配都会影响模块中的变量。
  • from foo import bar仅将给定名称绑定(foo即将保持未绑定)到具有相同名称的元素 in foo- 因此操作的bar行为如前所述。
  • from foo import *行为与前一个类似,但它导入所有不带下划线前缀的全局名称。如果模块__all__只定义了这个序列内的名称,则导入。

第 3 部分(您的问题中甚至不存在:p)

python 文档非常好,而且通常很冗长——您可以在其中找到几乎所有可能与语言相关的问题的答案。以下是一些有用的链接:

于 2012-05-08T15:33:01.403 回答
3

要回答您的第一个问题:

不,python 不会被“导入”两次。当 python 加载一个模块时,它会检查sys.modules. 如果它不在那里,则将其放入并加载。

回答你的第二个问题:

模块可以定义它们将导出到from camelot import *场景的名称,行为是为现有值创建名称,而不是引用现有变量(python 没有引用)。

在一个有点相关的话题上,做 afrom camelot import *常规 import 不同

于 2012-05-08T15:46:29.900 回答