Python `包裹上的del`有某种记忆

Python `包裹上的del`有某种记忆,python,python-3.x,ipython,packages,del,Python,Python 3.x,Ipython,Packages,Del,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

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'
[1]中的
:导入数学
在[2]中:math.cos(0)
Out[2]:1.0
在[3]中:del math.cos
在[4]中:math.cos(0)
---------------------------------------------------------------------------
AttributeError回溯(最近一次呼叫上次)
在()
---->1数学cos(0)
AttributeError:模块“math”没有属性“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
[5]中的
:del math
在[6]中:math.cos(0)
---------------------------------------------------------------------------
NameError回溯(最近一次呼叫上次)
在()
---->1数学cos(0)
NameError:未定义名称“math”
所以,正如所料,数学本身已经不复存在了

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

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'
[7]中的
:导入数学
[8]中:math.cos(0)
---------------------------------------------------------------------------
AttributeError回溯(最近一次呼叫上次)
在()
---->1数学cos(0)
AttributeError:模块“math”没有属性“cos”
因此,InteractivePython记得math.cos是在我们删除整个math包并再次导入它之后被专门删除的


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

一个包只从磁盘读取一次,然后作为可变单例存储在内存中。第二次导入时,您会得到与以前导入的完全相同的单例,但它仍然缺少其
cos
del math
只是删除了它的本地名称,它并没有从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版本之间的差异,
reload
import
将在后续问题中讨论:)

del math
根本不删除包,它只是删除当前模块中的本地名称
math

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

尤其是,
sys.modules
始终是所有已加载模块的字典,因此至少那里始终有一个引用

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


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

要添加更多细节,第二个
导入数学
将在
sys.modules
中查找加载的(仍然是变异的)模块,并跳过从磁盘再次加载的任何尝试。您可以尝试从
sys.modules
中删除它以强制重新加载,或者使用
importlib
,等等。正如我在下面和其他地方的评论中所说,在python 3.6.4中重新加载对我没有帮助。这是一个重新加载错误还是什么@我不明白你的评论。如果执行
导入数学
然后
删除数学.cos
然后
重新加载(数学)
,则
数学.cos
再次可用,因为
重新加载
会重新执行模块初始化,并在
系统模块
中重新填充模块的字典。
reload
的一个怪癖是它会保留额外的属性。因此,如果您手动创建了
math.foo
,那么当您
reload(math)
时,
math.foo
将保留。@ely reload在我的python 3.6.4上不起作用。请参阅上面评论中的链接。@A请继续提问,以了解Python 3.6中奇怪的重新加载行为。恐怕重新加载(math)不会重新引入math.cos函数(至少在我的机器上是这样)。关于这个话题,我有一个单独的问题:是的,我编辑的目的是展示一个不需要重新加载的版本。我不知道他为什么需要它,但这是了解它是如何工作的一个好方法。1)使用标准库并不意味着你可能对非标准库感兴趣。2)它让你了解库机制是如何工作的,这可能会对时间流逝、资源使用、硬盘访问、库中的静态变量等产生影响。3)它让你了解解释器如何处理某些问题,并将其转换为另一个类似的问题,甚至让你的曾经的解释器,或使它更好地满足好奇心。这是打开知识之门的钥匙。正如我父亲所说:打破僵局,你就会学习。你永远不知道你的好奇心会带你走多远。我父亲还说:怀疑的时候就是学习的时候(把任何怀疑当作学习的灵感)。另外,艾萨克·阿西莫夫在预测互联网时所说的好奇心也很有趣。