【问题标题】:How to delete a function argument early?如何尽早删除函数参数?
【发布时间】:2016-11-25 03:25:04
【问题描述】:

我正在编写一个函数,它需要一个巨大的参数,并且运行了很长时间。它只需要中途论证。如果没有更多的引用,函数有没有办法删除参数指向的值?

我可以在函数返回后立即将其删除,如下所示:

def f(m):
  print 'S1'
  m = None
  #__import__('gc').collect()  # Uncommenting this doesn't help.
  print 'S2'
class M(object):   
  def __del__(self):
    print '__del__'
f(M())

打印出来:

S1
S2
__del__

我需要:

S1
__del__
S2

我也尝试过def f(*args):def f(**kwargs),但没有帮助,我最后还是得到了__del__

请注意,我的代码依赖于 Python 具有引用计数这一事实,并且一旦对象的引用计数降至零,__del__ 就会被调用。我希望函数参数的引用计数在函数中间降为零。这可能吗?

请注意,我知道一种解决方法:传递参数列表:

def f(ms):
  print 'S1'
  del ms[:]
  print 'S2'
class M(object):   
  def __del__(self):
    print '__del__'
f([M()])

打印出来:

S1
__del__
S2

有没有办法在不更改 API 的情况下提前删除(例如,将列表引入参数)?

如果很难获得适用于许多 Python 实现的可移植解决方案,我需要一些适用于最新 CPython 2.7 的解决方案。不必记录在案。

【问题讨论】:

  • 你为什么要这样做?一般来说,我认为 python 不会在引用计数达到 0 时立即进行垃圾收集,但只会在一段时间后(未定义)。您应该能够强制进行垃圾回收。
  • 参数是从调用者的作用域传入的。最终该对象仍然在那里被引用。无论您将函数中的引用计数降低多少,直到您的函数结束,该对象可能都不会被垃圾收集,因为尚未清理父范围的引用。 – 这在很大程度上只是一个猜测,我不知道foo(m)foo(M()) 之间的行为会有什么不同;逻辑规定它不应该不同,但这也取决于实现。
  • 想说,即使你取消绑定参数,它仍然存在于函数范围之外。
  • 最后你不应该依赖 Python 的内部来进行内存管理。尽量减少内存消耗的最佳方法是以不同的方式解决问题,并以保证使用更少内存的方式实现它;例如通过从磁盘等读取流。
  • 你永远无法知道何时或指望__del__() 被调用,除非你自己明确地这样做。 Python 不是 C++。

标签: python python-2.7 destructor reference-counting


【解决方案1】:

来自the documentation

CPython 实现细节:CPython 目前使用引用计数方案,对循环链接的垃圾进行(可选)延迟检测,该方案在大多数对象变得无法访问时立即收集它们,但不能保证收集包含循环引用的垃圾。有关控制循环垃圾收集的信息,请参阅 gc 模块的文档。其他实现的行为不同,CPython 可能会改变。 当对象变得无法访问时,不要依赖于立即完成对象(例如:始终关闭文件)。

如果不自己修改解释器,你无法实现你想要的。 __del__ 将在解释器决定时调用。

【讨论】:

  • 或者你自己调用。即使那样,内存也可能不会立即被回收,如果有的话。
  • 感谢您的报价。它证明了在 CPython 中没有记录在案且面向未来的方法。我已经澄清了这个问题:我什至可以接受在 CPython 2.7 中工作的无证解决方案。
  • @martineau:手动调用m.__del__() 对我没有帮助。我不需要调用__del__,我只是使用__del__ 作为Python 解释器想要删除对象的指示符。我关心对象被提早删除。
  • 您可以使用gc.collect() 手动运行垃圾收集器,但这将收集待处理的所有内容,而不仅仅是您的一个对象,这可能需要比您想要的更长的时间。
  • @chepner:在m = None 之后运行gc.collect() 没有帮助,在函数返回之前,对象仍然不会被删除。
【解决方案2】:

如果不更改 f 函数的 API,似乎无法在 CPython 2.7 中进行早期删除。

【讨论】:

    猜你喜欢
    • 2018-07-26
    • 2016-02-16
    • 2016-11-08
    • 1970-01-01
    • 2018-11-04
    • 2023-04-03
    • 2019-08-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多