无法从 python 2.7 中的 atexit 注销函数
Cannot unregister functions from atexit in python 2.7
首先我用flush方法写了一个记录class:
class Recorder
def __init__(self, buffer_size, path):
self._big_buffer = np.array(*buffer_size)
self._path = path
def push(self, data):
# insert in self._big_buffer
# if self._big_buffer is full:
# self._flush()
def flush(self):
# write buffer to disk (self._path)
然后,我想在退出时刷新:当手动停止、崩溃或任何原因时。
所以我用了:
def __init__(self):
(...)
atexit.register(self.flush)
而且效果很好。
但是现在,我想记录,停止记录,再次记录,多次,不同的缓冲区大小和不同的路径。所以我必须丢弃,然后实例化几个Recorder
。它有点工作,但是旧 Recorder
的内存(包含一些 fat self._big_buffer̀
)没有被释放,因为它被 atexit
保留。即使我明确调用 del
。
我不能 atexit.unregister(self._flush)
因为它只有 Python 3。
我不希望重用现有实例,而是丢弃旧实例并创建新实例。
遇到这种情况你会怎么处理?
您可以尝试使用对 atexit
处理程序的弱引用,这样对象
如果在其他地方被删除,将不会被保留:
import atexit
import weakref
class CallableMethodWeakRef:
def __init__(self, object, method_name):
self.object_ref = weakref.ref(object)
self.method_name = method_name
def __call__(self):
object = self.object_ref()
if object:
getattr(object, self.method_name)()
class Recorder:
def __init__(self, *args):
atexit.register(CallableMethodWeakRef(self, 'flush'))
def flush(self):
print 'flushing'
该方法作为字符串传递以避免很多问题
绑定方法弱引用,如果你觉得它令人不安,你可以随时使用
像这样的 BoundMethodWeakref
实现:http://code.activestate.com/recipes/578298-bound-method-weakref/
答案 肯定是 允许您的 Recorder
随意更改路径和缓冲区特性。你说 "I would prefer not to reuse existing instances, but discarding older instances and create new ones." 但你没有给出任何理由,
也许除了你假设 "older Recorder's memory (containing some fat self._big_buffer̀
) is not freed since it's retained by atexit
",我认为这是不正确的。
虽然 atexit
确实保留了对记录器对象的引用,但这仅意味着只要记录器引用它,就会保留缓冲区内存。添加 close()
方法如
会很容易
def close(self):
self.flush()
self._big_buffer = None
还有宾果游戏!不存在对缓冲存储器的引用,并且它是可收集的。
你的 __init__()
方法应该简单地注册到 atexit
,然后 open()
方法(它完成 __init__()
当前所做的其余部分)可以多次使用, 每个后跟一个 close()
调用。
总而言之,我认为您的问题需要一个对象。
我会说您尝试使用错误的工具。 with
语句和上下文管理器是一个很好的工具。文件 IO 是大多数 python 用户将了解 with 语句的主要示例。
f = open("somefile.txt", "w")
try:
f.write("...")
# more file operations
finally:
# regardless of what happens, make sure the files is closed
f.close()
变为:
with open("somefile.txt", "w") as f:
f.write("...")
# more file operations
# close automatically called at the end of the block
您可以通过为 class.
编写 __enter__
和 __exit__
方法来创建自己的上下文管理器
class Recorder
def __init__(self, buffer_size, path):
self._big_buffer = np.array(*buffer_size)
self._path = path
def push(self, data):
# insert in self._big_buffer
# if self._big_buffer is full:
# self._flush()
def flush(self):
# write buffer to disk (self._path)
def __enter__(self):
return self
def __exit__(self, exctype, exception, traceback):
# If an exception was thrown in the with block you will get the details here.
# If you want the say that the exception has been handled and for it not to be
# raised outside the with block then return True
self.flush()
# self.close() ?
然后您可以像这样使用 Recorder
对象:
with Recorder(...) as recorder:
# operations with recorder
...
# regardless of what happens the recorder will be flushed at this point
您可以从(未记录的)atexit._exithandlers
列表中手动删除句柄。
import atexit
def unregister(func, *targs, **kargs):
"""unregister a function previously registered with atexit.
use exactly the same aguments used for before register.
"""
for i in range(0,len(atexit._exithandlers)):
if (func, targs, kargs) == atexit._exithandlers[i] :
del atexit._exithandlers[i]
return True
return False
希望对您有所帮助。
首先我用flush方法写了一个记录class:
class Recorder
def __init__(self, buffer_size, path):
self._big_buffer = np.array(*buffer_size)
self._path = path
def push(self, data):
# insert in self._big_buffer
# if self._big_buffer is full:
# self._flush()
def flush(self):
# write buffer to disk (self._path)
然后,我想在退出时刷新:当手动停止、崩溃或任何原因时。
所以我用了:
def __init__(self):
(...)
atexit.register(self.flush)
而且效果很好。
但是现在,我想记录,停止记录,再次记录,多次,不同的缓冲区大小和不同的路径。所以我必须丢弃,然后实例化几个Recorder
。它有点工作,但是旧 Recorder
的内存(包含一些 fat self._big_buffer̀
)没有被释放,因为它被 atexit
保留。即使我明确调用 del
。
我不能 atexit.unregister(self._flush)
因为它只有 Python 3。
我不希望重用现有实例,而是丢弃旧实例并创建新实例。
遇到这种情况你会怎么处理?
您可以尝试使用对 atexit
处理程序的弱引用,这样对象
如果在其他地方被删除,将不会被保留:
import atexit
import weakref
class CallableMethodWeakRef:
def __init__(self, object, method_name):
self.object_ref = weakref.ref(object)
self.method_name = method_name
def __call__(self):
object = self.object_ref()
if object:
getattr(object, self.method_name)()
class Recorder:
def __init__(self, *args):
atexit.register(CallableMethodWeakRef(self, 'flush'))
def flush(self):
print 'flushing'
该方法作为字符串传递以避免很多问题
绑定方法弱引用,如果你觉得它令人不安,你可以随时使用
像这样的 BoundMethodWeakref
实现:http://code.activestate.com/recipes/578298-bound-method-weakref/
答案 肯定是 允许您的 Recorder
随意更改路径和缓冲区特性。你说 "I would prefer not to reuse existing instances, but discarding older instances and create new ones." 但你没有给出任何理由,
也许除了你假设 "older Recorder's memory (containing some fat self._big_buffer̀
) is not freed since it's retained by atexit
",我认为这是不正确的。
虽然 atexit
确实保留了对记录器对象的引用,但这仅意味着只要记录器引用它,就会保留缓冲区内存。添加 close()
方法如
def close(self):
self.flush()
self._big_buffer = None
还有宾果游戏!不存在对缓冲存储器的引用,并且它是可收集的。
你的 __init__()
方法应该简单地注册到 atexit
,然后 open()
方法(它完成 __init__()
当前所做的其余部分)可以多次使用, 每个后跟一个 close()
调用。
总而言之,我认为您的问题需要一个对象。
我会说您尝试使用错误的工具。 with
语句和上下文管理器是一个很好的工具。文件 IO 是大多数 python 用户将了解 with 语句的主要示例。
f = open("somefile.txt", "w")
try:
f.write("...")
# more file operations
finally:
# regardless of what happens, make sure the files is closed
f.close()
变为:
with open("somefile.txt", "w") as f:
f.write("...")
# more file operations
# close automatically called at the end of the block
您可以通过为 class.
编写__enter__
和 __exit__
方法来创建自己的上下文管理器
class Recorder
def __init__(self, buffer_size, path):
self._big_buffer = np.array(*buffer_size)
self._path = path
def push(self, data):
# insert in self._big_buffer
# if self._big_buffer is full:
# self._flush()
def flush(self):
# write buffer to disk (self._path)
def __enter__(self):
return self
def __exit__(self, exctype, exception, traceback):
# If an exception was thrown in the with block you will get the details here.
# If you want the say that the exception has been handled and for it not to be
# raised outside the with block then return True
self.flush()
# self.close() ?
然后您可以像这样使用 Recorder
对象:
with Recorder(...) as recorder:
# operations with recorder
...
# regardless of what happens the recorder will be flushed at this point
您可以从(未记录的)atexit._exithandlers
列表中手动删除句柄。
import atexit
def unregister(func, *targs, **kargs):
"""unregister a function previously registered with atexit.
use exactly the same aguments used for before register.
"""
for i in range(0,len(atexit._exithandlers)):
if (func, targs, kargs) == atexit._exithandlers[i] :
del atexit._exithandlers[i]
return True
return False
希望对您有所帮助。