无法从python 2.7

时间:2015-08-19 14:13:24

标签: python python-2.7 garbage-collection atexit

首先,我用flush方法编写了一个录制类:

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的旧self._big_buffer̀内存(含有一些胖atexit)没有被释放,因为它被del保留了。即使我明确地呼叫atexit.unregister(self._flush)。 我不能POST,因为它只是Python 3。

我不想重复使用现有实例,而是放弃旧实例并创建新实例。

你会如何处理这种情况?

4 个答案:

答案 0 :(得分:4)

您可以尝试使用对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/

答案 1 :(得分:2)

我会说你试图使用错误的工具。 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

您可以为您的班级编写__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

答案 2 :(得分:0)

答案 肯定是允许class Program { static void Main(string[] args) { Random rand = new Random(); int number = rand.Next(1, 1000); byte[] intBytes = BitConverter.GetBytes(number); string answer = ""; for (int i = 0; i < intBytes.Length; i++) { answer += intBytes[i] + @"\"; } Console.WriteLine(answer); Console.WriteLine(number); Console.ReadKey(); } } 随意更改路径和缓冲区特征。你说&#34;我不想重复使用现有的实例,而是放弃旧的实例并创建新的实例。&#34; 但是你没有给出任何理由, 除了你假设&#34;较旧的记录器的记忆(包含一些胖Recorder)没有被释放,因为它被self._big_buffer̀&#34;保留了。 ,我认为这是不正确的。

虽然atexit确实保留了对记录器对象的引用,但这只意味着只要记录器引用它就会保留缓冲存储器。添加atexit方法非常容易,例如

close()

和宾果游戏!不存在对缓冲存储器的引用,它是可收集的。

您的 def close(self): self.flush() self._big_buffer = None 方法应该只使用__init__()注册,然后atexit方法(执行open()当前所做的其余工作)可以多次使用,每个一个接着是__init__()电话。

总之,我认为你的问题需要一个对象。

答案 3 :(得分:0)

您可以从(未公开)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

希望有帮助。