有没有一种方法可以从解释器的内存中删除已创建的变量、函数等?

179

我已经搜索了几天这个问题的精确答案,但没有得到什么好的东西。虽然我不是编程的完全初学者,但还没有达到中级水平。

当我在Python的shell中时,我输入:dir(),就可以看到当前作用域(主块)中所有对象的名称,共有6个:

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

例如,当我声明一个变量时,比如 x = 10,它会自动添加到内置模块 dir() 的对象列表中,当我再次输入 dir() 时,它现在会显示如下:

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'x']

同样适用于函数、类等。
如何删除所有这些新的对象,而不擦除一开始可用的那 6 个标准对象?
我在这里读到了关于“内存清理”、“控制台清理”的内容,这将擦除命令提示窗口中的所有文本:
>>> import sys
>>> clear = lambda: os.system('cls')
>>> clear()

但这与我试图实现的目标无关,它并不能清除所有已使用的对象。


2
你为什么觉得需要这样做,还是只是出于好奇而问? - PM 2Ring
1
哦,顺便说一句,del不是一个函数,因此没有。它是一个关键字,引入了一个del语句。当然,它实际上如何删除一个对象可能涉及函数,但那又是另外一个故事... - PM 2Ring
可能是重复的问题:如何在 Python 脚本中清除所有变量? - smac89
@Smac89:我认为我的问题的答案更好,因为它们包含了额外的信息,并且比参考问题提供的答案要简单得多。即使答案更好,它仍然应该被视为重复并被删除吗?谢谢。 - rombez
1
我通过谷歌找到了这个问题,现在我想知道 - 如果我想要删除所有变量和函数,为什么不能只是重新启动内核并从顶部重新运行脚本呢? - vagabond
显示剩余2条评论
8个回答

234

您可以使用del删除单个名称:

del x

或者你可以从 globals() 对象中删除它们:

for name in dir():
    if not name.startswith('_'):
        del globals()[name]

这只是一个示例循环; 它防御性地仅删除不以下划线开头的名称,做出了一个(不无理由的)假设,即您在解释器中仅使用不带下划线开头的名称。 如果您确实想彻底一些,可以使用硬编码的名称列表来保留(白名单)。 除了退出并重新启动解释器之外,没有内置函数可以为您清除。

导入的模块(import os)将保持导入状态,因为它们被sys.modules引用; 后续的导入将重用已经导入的模块对象。 但是你当前的全局命名空间中将没有对它们的引用。

然而,Python不对内存中的数据做任何安全保证。 当对象不再被引用时,解释器会将该内存标记为不再使用,但不会采取措施覆盖该内存以防止访问数据。 如果您需要那种级别的安全保护,您需要使用管理自己内存的第三方扩展,并考虑安全性。


3
@georg:我已经为循环编写了防御性代码。如果你想做得更好,你需要硬编码一个初始的名字列表来保留。 - Martijn Pieters
1
@georg:不,解释器的全局命名空间也因版本而异,并且没有绝对可靠的方法(至少我不知道)来枚举在稍后打开解释器时其中包含了什么。 - Martijn Pieters
1
@nakE 函数和类就像任何其他对象一样。它们并不特殊,如果需要保留类和函数,请使用白名单或检查对象类型。 - Martijn Pieters
@SurpriseDog 这并不是问题所在。这里没有安全保障,只是Python解释器忘记了这个名字。 - Martijn Pieters
@MartijnPieters 必须有一种方法可以覆盖内存中的变量。我以为创建足够多的垃圾数据就可以了,但我不明白为什么这样不起作用。 - SurpriseDog
显示剩余10条评论

95

是的,在 iPython 中有一种简单的方法可以删除所有内容。 只需在 iPython 控制台中键入:

%reset

然后系统会要求您确认。按 y 键。 如果您不想看到此提示,请直接输入:

%reset -f

这应该能够工作..


2
为什么这个答案不是最佳答案呢? - myradio
43
因为这个问题只与使用 IPython 的人有关,对其他人而言不相关。此外,它也没有回答问题;问题是要求删除全局对象引用,而不是重置 IPython shell 的内容。 - Andreas detests censorship
2
这是我在Jupyter Notebook中寻找的魔法命令,可以清除变量(以释放CPU/GPU内存),而无需重新启动内核! - Gorkem

31

您可以使用Python垃圾回收器:

import gc
gc.collect()

11
嘿@Fardin!谢谢!你的答案解决了我的问题,救了我的一天!但是在gc.collect()之前,我执行了del(variable)。 - Gmosy Gnaq
9
gc.collect()本身不起作用。就像Gmosy上面提到的那样,必须使用del(变量名)。 - Nguai al
gc.collect()似乎没有起作用。所有变量仍然可以访问。 - Peter Leopold
垃圾回收仅清理不再被引用的内存对象。问题在于如何删除这些引用。垃圾回收会自动运行,通常无需手动触发。 - mkrieger1

13

这应该能解决问题。

globals().clear()

最好加一行说明为什么这样做有效! - Anurag A S
1
这是在基本的python shell中运行的唯一有效建议。 - Peter Leopold
1
这比我以前用del globals()[name]逐个变量删除的方式,释放了超过50%的物理和虚拟内存。我正在Spyder中运行脚本,仍在努力找出剩下40%的内存去向... - Larry Panozzo
这是唯一对我有效的答案!有没有办法做到这一点,使我们不必再次运行“import numpy”命令? - Nike

12

如果您在类似于Jupyteripython这样的交互式环境中,可能会对清除不需要的变量感兴趣,尤其是当它们占用过多内存时。

ipythonJupyter这样的交互式Python会话中提供了魔术命令resetreset_selective.

1) reset

  

reset将用户定义的所有名称从命名空间中删除,如果没有参数调用,则重置命名空间。

inout参数指定是否要刷新输入/输出缓存。使用dhist参数可以刷新目录历史记录。

reset in out

另一个有趣的是array,它只删除numpy数组:

reset array

2) reset_selective

重置命名空间,删除用户定义的名称。输入/输出历史记录保留在原地,以防需要使用它们。

干净的数组示例:

In [1]: import numpy as np
In [2]: littleArray = np.array([1,2,3,4,5])
In [3]: who_ls
Out[3]: ['littleArray', 'np']
In [4]: reset_selective -f littleArray
In [5]: who_ls
Out[5]: ['np']

来源: http://ipython.readthedocs.io/en/stable/interactive/magics.html


10

实际上,Python会回收不再使用的内存。这被称为垃圾回收,是Python中的自动过程。但是如果您仍然想要回收它,那么可以通过del variable_name删除它。您也可以将变量赋值为None来回收内存。

a = 10
print a 

del a       
print a      ## throws an error here because it's been deleted already.

从未被引用的 Python 对象中真正回收内存的唯一方式是通过垃圾收集器。del 关键字只是将名称与对象解除绑定,但对象仍然需要进行垃圾回收。您可以使用 gc 模块强制运行垃圾回收器,但这几乎肯定是过早优化,而且它也有自己的风险。使用 del 没有实际效果,因为这些名称在超出其范围时会被删除。


1
当然,在解释器的全局命名空间中工作时,名称不会超出范围,但这有什么关系呢。 :) 我想值得一提的是,已经被垃圾回收的对象使用的内存的处理方式取决于实现,但在大多数Python实现中,已经被垃圾回收的内存仅返回到Python池中,直到程序退出才返回到操作系统。 - PM 2Ring
@PM2Ring 哈哈 :) 我也这么认为。你从哪里获取 Python 相关的参考资料呢? - d-coder
2
请注意,在CPython中,GC仅需要打破引用循环。如果没有剩余引用,对象将被立即从内存中删除。因此,在这里del确实有真正的效果。 - Martijn Pieters
2
@eryksun:是的,当然是根据 RFC 4042-bis2 定义的!:-P - Martijn Pieters
None选项非常强大。如果您有一个大的数据框,并且想要停止使用内存空间,只需执行:myDataframe = None - alepaff
显示剩余3条评论

3
这对我很有帮助。
你需要运行两次,一次全局变量,一次本地变量。
for name in dir():
    if not name.startswith('_'):
        del globals()[name]

for name in dir():
    if not name.startswith('_'):
        del locals()[name]

2
通过 locals() 获取的字典对象无法被修改,因此在其上使用 del 也是无效的。 - Andy

-1

дҪ еҸҜд»ҘдҪҝз”ЁdelиҜӯеҸҘеҲ йҷӨPythonдёӯзҡ„еҸҳйҮҸ

дҫӢеҰӮпјҡ

y = 10 del y

еҰӮжһңдҪ иҜ•еӣҫдҪҝз”ЁжҲ–еј•з”Ёе·ІеҲ йҷӨзҡ„еҸҳйҮҸпјҢдҪ е°Ҷдјҡеҫ—еҲ°жңӘе®ҡд№үзҡ„й”ҷиҜҜгҖӮ


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