python - 如何清除 stringio 对象?

标签 python stringio

我创建了一个 stringio 对象,其中包含一些文本。我想清除其现有值并重用它而不是召回它。有没有办法做到这一点?

最佳答案

TL;DR

不必费心清除它,只需创建一个新的——它会更快。

方法

Python 2

以下是我如何找到这些东西的方法:

>>> 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 提供 pointing out the difference 。)

>>> 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 对象!

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% ),但是创建一个新的 cStringIO.StringIO 更快(“更快”)(对于空的数据快 8%,对于 3KB 的数据快 10%)。所以我建议只使用最简单的——假设你正在使用 CPython,使用 cStringIO 并创建新的。

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,创建一个新的而不是重用一个空白的要快 11%,而创建一个新的而不是重用一个 3K 的要快 5%。同样,创建一个新的 StringIO 而不是截断和查找。

关于python - 如何清除 stringio 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4330812/

相关文章:

python - 使用 SqlAlchemy 执行原始查询(在 SQL-Server 数据库和 Pymssql 上)时,传递的参数无法识别并引发 SQL 错误

python - 三角分布随机变量

python - 何时在 Python 中使用线程本地内存?

python - ParseError : "ValidateError Field(s) ` arch` failed : Invalid view definition Error details: Model not found: forecast. 报告

python - 有没有办法让StringIO读取阻塞

python flask : Download a file generated on the fly AND print a response

python-3.x - tempfile 模块和 IO 类文件对象有什么区别

python - Python3 Django 的多对多关系中的 .add( ) 函数不起作用

python - 为什么 StringIO 对象比真实文件对象慢?

python json转储可写性 "not write able"