Engineer in Tokyo

Python StringIO と cStringIO のもう一つの違い

C で作られたcStringIOはピュアPythonで作られたStringIOモジュールと違うのをみんな知っていると思いますけど、今日、私が知らなかった違いをもう一つ見つけました。

StringIOでは、StringIOのコンストラクターに文字列を渡せば、その文字列に書き込みすることができる。

>>> from StringIO import StringIO
>>> writer = StringIO('a')
>>> writer.seek(1)
>>> writer.write("b")
>>> writer.getvalue()
'ab'

だが、cStringIOの場合、コンストラクターに文字列を渡せば、StringIO.StringIオブジェクトになって、writeメソッドがそもそもないオブジェクトになります。

>>> from cStringIO import StringIO
>>> writer = StringIO('a')
>>> writer
<cStringIO.StringI object at 0xb74b3530>
>>> writer.write("b")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'cStringIO.StringI' object has no attribute 'write'

解決するのがそんなに難しくないけど、AttributeErrorが出て、ビックリしました。

解決するのはこう書けばいい。

>>> from cStringIO import StringIO
>>> x = 'a' # 既存文字列
>>> writer = StringIO()
>>> writer.write(x)
>>> writer.write('b')
>>> writer.getvalue()
'ab'

私は具体的に、やろうとしていたのは、 Django のdjango.core.files.baseContentFileを使おうとしていた。だが、どうしても、StringIOのコンストラクターに文字列を渡すので、書き込みには使い物にならなかった。

>>> from cStringIO import StringIO
>>> from django.core.files.base import File, ContentFile
>>> f = ContentFile(None)
>>> f.write('a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ian/.virtualenvs/django-test/lib/python2.5/site-packages/django/core/files/utils.py", line 24, in <lambda>
    write = property(lambda self: self.file.write)
AttributeError: 'cStringIO.StringI' object has no attribute 'write'
>>> f = File(StringIO())
>>> f.write('a')
>>> f.seek(0)
>>> f.read()
'a'