包上的 `del` 有某种记忆

`del` on a package has some kind of memory

del 好像有一些记忆让我很困惑。请参阅以下内容:

In [1]: import math

In [2]: math.cos(0)
Out[2]: 1.0

In [3]: del math.cos

In [4]: math.cos(0)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-9cdcc157d079> in <module>()
----> 1 math.cos(0)

AttributeError: module 'math' has no attribute 'cos'

很好。让我们看看如果我们删除整个数学包会发生什么:

In [5]: del math

In [6]: math.cos(0)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-6-9cdcc157d079> in <module>()
----> 1 math.cos(0)

NameError: name 'math' is not defined

所以,正如预期的那样,现在数学本身已经消失了。

现在让我们再次导入数学:

In [7]: import math

In [8]: math.cos(0)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-9cdcc157d079> in <module>()
----> 1 math.cos(0)

AttributeError: module 'math' has no attribute 'cos'

所以不知何故互动 python 即使我们删除了整个数学包并再次导入它,也记得 math.cos 被专门删除了。

python 在哪里保存这些知识?我们可以访问它吗?我们可以改变它吗?

包只从磁盘读取一次,然后作为可变单例存储在内存中。第二次导入它时,您会得到与之前导入的完全相同的单例,但它仍然缺少 cosdel math 只是删除它的本地名称,它不会 "unimport" 从 Python 整体删除包。

我会说这个包仍然被视为进口的。所以再次执行 import math 只是重新声明名称,但内容是旧的。

您可以使用 reload 来确保您的模块再次完整,除了 python 的某些版本还需要删除 sys.modules 中的条目,这使得使用reload 冗余:

import math
del math.cos
del math
sys.modules.pop("math")   # remove from loaded modules
import math
print(math.cos(0))  # 1.0

(各种 python 版本、reloadimport 之间的差异在后续问题中讨论:

del math根本不删除包,只是删除当前模块中的local namemath

与任何其他对象一样,如果对数学模块的任何其他引用存在于任何地方,那么它会保存在内存中。

特别是,sys.modules 始终是所有已加载模块的字典,因此至少总有一个引用。

编辑:但是有一种方法可以实际重新加载模块,imp.reload

不幸的是,我无法让它在这种情况下工作,重新加载需要随机模块(可能要创建已编译的 Python 文件的某些部分),随机模块需要 math.cos,它不见了。即使先导入 random 也没有错误,但是 math.cos 不会重新出现;我不知道为什么,可能是因为它是一个内置模块。