我已经创建了一个StringIO对象,并在其中添加了一些文本。我想要清除它现有的值,以便重复使用它,而不是重新调用它。有没有任何方法可以做到这一点?
不要费力清除,直接创建一个新的--这样会更快。
以下是我查找此类信息的方法:
>>> 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可能会更便宜(和更容易)。请参见下面的基准测试。
(感谢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 时代码出现问题。另外,创建一个新的 StringIO
对象也是一个很好的选择!
>>> 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
使用StringIO存储3KB的数据:
>>> 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%更快),但是创建一个新的 cStringIO.StringIO
更快(空字符串8%更快,3KB数据10%更快)。所以我建议只使用最简单的方法 - 假设您正在使用CPython,请使用cStringIO
并创建新的实例。
相同的代码,只需添加 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来说,创建一个新的空白对象比重复使用空白对象更快11%,创建一个新的而不是重用3K对象会更快5%。同样,创建一个新的StringIO
对象而不是截断和搜索。
有一点需要注意(至少对于Python 3.2而言):
在使用truncate(0)之前需要调用seek(0)。这是一段没有调用seek(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'
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()
StringIO
和cStringIO
)?我很想看看它们。 - Chris Morganreset
方法已经不存在了:'_io.StringIO' object has no attribute 'reset'
! - mds