我如何清除一个弦乐对象?

我有一个创build的弦乐对象,它有一些文字。 我想清除其现有的价值,并重用它,而不是回顾它。 有没有这样做?

TL; DR

不要打扰它,只是创build一个新的 – 它更快。

方法

Python 2

以下是我如何find这样的事情:

>>> from StringIO import StringIO >>> dir(StringIO) ['__doc__', '__init__', '__iter__', '__module__', 'close', 'flush', 'getvalue', 'isatty', 'next', 'read', 'readline', 'readlines', 'seek', 'tell', 'truncate', 'write', 'writelines'] >>> help(StringIO.truncate) Help on method truncate in module StringIO: truncate(self, size=None) unbound StringIO.StringIO method Truncate the file's size. If the optional size argument is present, the file is truncated to (at most) that size. The size defaults to the current position. The current file position is not changed unless the position is beyond the new file size. If the specified size exceeds the file's current size, the file remains unchanged. 

所以,你想.truncate(0) 。 但是初始化一个新的StringIO可能更便宜(也更容易)。 见下面的基准。

Python 3

(感谢tstone2077 指出的差异 。)

 >>> from io import StringIO >>> dir(StringIO) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', 'close', 'closed', 'detach', 'encoding', 'errors', 'fileno', 'flush', 'getvalue', 'isatty', 'line_buffering', 'newlines', 'read', 'readable', 'readline', 'readlines', 'seek', 'seekable', 'tell', 'truncate', 'writable', 'write', 'writelines'] >>> help(StringIO.truncate) Help on method_descriptor: truncate(...) Truncate size to pos. The pos argument defaults to the current file position, as returned by tell(). The current file position is unchanged. Returns the new absolute position. 

这一点很重要,现在当前的文件位置是不变的 ,而截断为零的大小会重置Python 2变体中的位置。

因此,对于Python 2,您只需要

 >>> from cStringIO import StringIO >>> s = StringIO() >>> s.write('foo') >>> s.getvalue() 'foo' >>> s.truncate(0) >>> s.getvalue() '' >>> s.write('bar') >>> s.getvalue() 'bar' 

如果你在Python 3中这样做,你不会得到你所期望的结果:

 >>> from io import StringIO >>> s = StringIO() >>> s.write('foo') 3 >>> s.getvalue() 'foo' >>> s.truncate(0) 0 >>> s.getvalue() '' >>> s.write('bar') 3 >>> s.getvalue() '\x00\x00\x00bar' 

所以在Python 3中,你也需要重置位置:

 >>> from cStringIO import StringIO >>> s = StringIO() >>> s.write('foo') 3 >>> s.getvalue() 'foo' >>> s.truncate(0) 0 >>> s.seek(0) 0 >>> s.getvalue() '' >>> s.write('bar') 3 >>> s.getvalue() 'bar' 

如果在Python 2代码中使用truncate方法,则同时调用seek(0)更安全(在之前或之后,这并不重要),以便在不可避免地将代码移植到Python 3时,代码不会中断。还有一个原因,你应该创build一个新的StringIO对象!

Python 2

 >>> from timeit import timeit >>> def truncate(sio): ... sio.truncate(0) ... return sio ... >>> def new(sio): ... return StringIO() ... 

当为空时,用StringIO:

 >>> from StringIO import StringIO >>> timeit(lambda: truncate(StringIO())) 3.5194039344787598 >>> timeit(lambda: new(StringIO())) 3.6533868312835693 

有了3KB的数据,用StringIO:

 >>> timeit(lambda: truncate(StringIO('abc' * 1000))) 4.3437709808349609 >>> timeit(lambda: new(StringIO('abc' * 1000))) 4.7179079055786133 

和cStringIO一样:

 >>> from cStringIO import StringIO >>> timeit(lambda: truncate(StringIO())) 0.55461597442626953 >>> timeit(lambda: new(StringIO())) 0.51241087913513184 >>> timeit(lambda: truncate(StringIO('abc' * 1000))) 1.0958449840545654 >>> timeit(lambda: new(StringIO('abc' * 1000))) 0.98760509490966797 

因此,忽略潜在的内存问题( del oldstringio ),截断一个StringIO.StringIO (空3%,3KB数据加快8%)速度更快,但创build一个新的cStringIO.StringIO速度更快(“紧固”) cStringIO.StringIO (空白8%,3KB数据快10%)。 所以我build议只使用最简单的一个 – 假设你正在使用CPython,使用cStringIO并创build新的。

Python 3

相同的代码,只需要seek(0)就可以了。

 >>> def truncate(sio): ... sio.truncate(0) ... sio.seek(0) ... return sio ... >>> def new(sio): ... return StringIO() ... 

空时:

 >>> from io import StringIO >>> timeit(lambda: truncate(StringIO())) 0.9706327870007954 >>> timeit(lambda: new(StringIO())) 0.8734330690022034 

在3KB的数据中:

 >>> timeit(lambda: truncate(StringIO('abc' * 1000))) 3.5271066290006274 >>> timeit(lambda: new(StringIO('abc' * 1000))) 3.3496507499985455 

所以Python 3创build一个新的,而不是重复使用一个空白的速度快11%,创build一个新的,而不是重新使用3K的速度快了5%。 再次创build一个新的StringIO而不是截断和寻找。

有一点需要注意(至less在Python 3.2中):

在截断(0)之前需要(0) IS 。 这里有一些代码没有寻求(0):

 from io import StringIO s = StringIO() s.write('1'*3) print(repr(s.getvalue())) s.truncate(0) print(repr(s.getvalue())) s.write('1'*3) print(repr(s.getvalue())) 

哪些产出:

 '111' '' '\x00\x00\x00111' 

与截断之前的seek(0),我们得到预期的输出:

 '111' '' '111' 

我如何设法优化序列中许多文件的处理(读取块,处理每个块,将处理后的stream写入文件)是我重复使用相同的cStringIO.StringIO实例,但总是在使用后reset() ,然后写入它,然后truncate() 。 通过这样做,我只截断了当前文件不需要的部分。 这似乎给了我〜3%的performance增加。 任何人谁更专家可以证实,如果这确实优化内存分配。

 sio = cStringIO.StringIO() for file in files: read_file_chunks_and_write_to_sio(file, sio) sio.truncate() with open('out.bla', 'w') as f: f.write(sio.getvalue()) sio.reset()