簡體   English   中英

如何清除弦樂對象?

[英]how do I clear a stringio object?

我創建了一個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 指出了區別 。)

>>> 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

使用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更快(也“更快”) 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 3.2中):

求(0)截斷之前需要 (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'

如何設法優化我的序列中多個文件的處理(讀入塊,處理每個塊,將處理后的流寫到文件)的方法是,我重用相同的cStringIO.StringIO實例,但始終在使用后將其reset() ,然后對其進行寫入,然后truncate() 這樣一來,我只會在不需要當前文件的最后部分截斷。 這似乎使我的性能提高了約3%。 任何對此有更高專業知識的人都可以確認這是否確實優化了內存分配。

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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM