【问题标题】:when does python delete variables?python什么时候删除变量?
【发布时间】:2014-10-06 19:31:20
【问题描述】:

我知道 python 有一个自动垃圾收集器,所以它应该在不再引用变量时自动删除变量。

我的印象是局部变量(函数内部)不会发生这种情况。

def funz(z):
    x = f(z) # x is a np.array and contains a lot of data
    x0 = x[0]
    y = f(z + 1) # y is a np.array and contains a lot of data
    y0 = y[0]

    # is x and y still available here?
    return y0, x0

del x 是节省内存的正确方法吗?

def funz(z):
    x = f(z) # x is a np.array and contains a lot of data
    x0 = x[0]
    del x
    y = f(z + 1) # y is a np.array and contains a lot of data
    y0 = y[0]
    del y

    return y0, x0

编辑:我已经编辑了我的示例,使其更类似于我的实际问题。 在我的真正问题中,x 和 y 不是列表,而是包含不同大 np.array 的类。

编辑:我能够运行代码:

x = f(z)
x0 = x[0]
print(x0)

y = f(z + 1)
y0 = [0]
print(y0)

【问题讨论】:

  • 我的印象是局部变量(函数内部)不会发生这种情况。 是什么让您有这种印象?函数结束时清除本地名称;当它们的引用计数下降到 0 时,它们引用的对象将被删除就像 Python 中的其他任何地方。
  • 我有一个函数可以运行一些独立的脚本。我收到内存不足错误。我知道我能够独立运行这些脚本
  • @Donbeo:当函数运行脚本时,你是如何运行它们的?它们是作为单独的进程还是作为模块运行?
  • @MartijnPieters OP 可能会因为 python 中的“范围”与许多其他语言中的“范围”不同而感到困惑。例如,for 循环没有定义新的作用域,其变量在最后一次迭代后仍然有效。

标签: python memory garbage-collection


【解决方案1】:

实现使用引用计数来确定何时应该删除变量。

在变量超出范围后(如您的示例),如果没有剩余的引用,那么内存将被释放。

def a():
    x = 5 # x is within scope while the function is being executed
    print x

a()
# x is now out of scope, has no references and can now be deleted

除了列表中的字典键和元素之外,通常很少有理由在 Python 中手动删除变量。

不过,正如this question 的回答中所说,使用 del 可以用于显示意图。

【讨论】:

  • 重要提示:垃圾收集和引用计数不是一回事,Python 两者兼而有之。然而,垃圾收集主要用于清理循环引用,因此不是内存管理的主要形式。引用计数会在引用计数降至零时立即释放内存,它不会等待 GC 周期。当然也有一些例外,因为 python 会缓存整数和短字符串,即使出于性能原因没有对它们的实时引用。
【解决方案2】:

这取决于实现和变量的类型。对于像 int 这样的简单对象,有一些优化。例如,在 CPython 中,一个简单的 int 将重用相同的内存,即使在使用了 del 之后也是如此。你不能指望这一点,但它确实说明事情比看起来更复杂。

请记住,当您del 时,您删除的是名称,不一定是对象。
例如:

# x is a np.array and contains a lot of data

更准确的措辞是:

# x references a np.array which contains a lot of data

del 将减少该对象的引用计数,但即使它降至零,也不能保证很快就会被垃圾回收。

建议您查看the gc module 以获得解释和灵感。然后再想一想。

如果您“内存不足”,那么您的设计可能存在根本问题。很可能您一次加载了太多数据(尝试使用迭代器?),或者您的代码可能需要更好地结构化。

我刚刚看到你的编辑。您是否需要同时在内存中使用所有该数组?你能用发电机吗?

另一种选择是使用 SQLite 之类的数据库,或者 shelve

【讨论】:

  • 是的,我需要所有的清单。这个例子不完全是我的代码。在我的代码中,f 返回一个类,其中该类中的某些元素很大 np.ndarray。如果我可以使用 del 之类的东西手动删除变量,那么我认为我的问题将得到解决
【解决方案3】:

将两个概念分开很重要:名称和值。 Python 中的变量是指一个值的名称。名称有作用域:当你定义一个局部变量时(通过给一个名字赋值),这个变量的作用域就是当前函数。当函数返回时,变量消失。但这并不意味着价值消失了。

值没有作用域:它们一直存在,直到没有更多名称引用它们为止。您可以在函数中创建一个值,然后从该函数返回它,使函数外部的名称引用该值,并且该值将不会被回收,直到将来所有对它的引用都消失了。

更多细节(包括图片!)在这里:Facts and Myths about Python Names and Values。

【讨论】:

    【解决方案4】:

    在单独的函数中写下你想从内存中清除的东西。在您的示例中,您可以这样做

      def xdef(z):
        x = f(z) # x is a np.array and contains a lot of data 
        x0 = x[0]
    
      def funz(z):
        xdef(z)
        y = f(z + 1) # y is a np.array and contains a lot of data
        y0 = y[0]  
    
        return y[0], x[0] 
    

    这会导致异常

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多