web-dev-qa-db-ja.com

TypeError: 'str'はバッファインタフェースをサポートしていません

plaintext = input("Please enter the text you want to compress")
filename = input("Please enter the desired filename")
with gzip.open(filename + ".gz", "wb") as outfile:
    outfile.write(plaintext) 

上記のPythonコードは私に次のようなエラーを出しています:

Traceback (most recent call last):
  File "C:/Users/Ankur Gupta/Desktop/Python_works/gzip_work1.py", line 33, in <module>
    compress_string()
  File "C:/Users/Ankur Gupta/Desktop/Python_works/gzip_work1.py", line 15, in compress_string
    outfile.write(plaintext)
  File "C:\Python32\lib\gzip.py", line 312, in write
    self.crc = zlib.crc32(data, self.crc) & 0xffffffff
TypeError: 'str' does not support the buffer interface
261
Future King

Python3xを使う場合、stringはPython 2.xと同じ型ではないので、それをバイトにキャスト(エンコード)する必要があります。

plaintext = input("Please enter the text you want to compress")
filename = input("Please enter the desired filename")
with gzip.open(filename + ".gz", "wb") as outfile:
    outfile.write(bytes(plaintext, 'UTF-8'))

また、stringfileのような変数名はモジュールや関数の名前ですが、使わないでください。

@Tomを編集

はい、ASCII以外のテキストも圧縮/解凍されます。私はUTF-8エンコーディングのポーランド文字を使います。

plaintext = 'Polish text: ąćęłńóśźżĄĆĘŁŃÓŚŹŻ'
filename = 'foo.gz'
with gzip.open(filename, 'wb') as outfile:
    outfile.write(bytes(plaintext, 'UTF-8'))
with gzip.open(filename, 'r') as infile:
    outfile_content = infile.read().decode('UTF-8')
print(outfile_content)
290
Michał Niklas

この問題に対するより簡単な解決策があります。

tをモードに追加するだけで、wtになります。これにより、Pythonはファイルをバイナリではなくテキストファイルとして開きます。それからすべてがうまくいくでしょう。

完全なプログラムはこれになります:

plaintext = input("Please enter the text you want to compress")
filename = input("Please enter the desired filename")
with gzip.open(filename + ".gz", "wt") as outfile:
    outfile.write(plaintext)
94
user1175849

Python 3 'string'を、何らかのエンコーディングへの明示的な変換なしでバイトにシリアル化することはできません。

outfile.write(plaintext.encode('utf-8'))

おそらくあなたが望むものです。また、これはpython 2.xと3.xの両方で機能します。

42
Andreas Jung

Python 3.xでは、テキストを生のバイトに変換することができます。

bytes("my data", "encoding")

例えば:

bytes("attack at dawn", "utf-8")

返されたオブジェクトはoutfile.writeで動作します。

28
Skurmedel

この問題は通常、py2からpy3に切り替えると発生します。 py2ではplaintext文字列バイト配列型の両方です。 py3ではplaintext文字列のみであり、outfileがバイナリモードで開かれている場合、メソッドoutfile.write()は実際にはバイト配列を取ります。発生します。問題を解決するために入力をplaintext.encode('utf-8')に変更してください。これがあなたを悩ませているなら読んでください。

Py2では、 file.writeの宣言 によって、file.write(str)という文字列を渡したように見えます。実際にはあなたはバイト配列を渡していました、あなたはこのような宣言を読んでいたはずです:file.write(bytes)。このように読めば問題は単純です、file.write(bytes) bytes typeを必要とし、py3では bytes から取り出すために必要です。 //] str あなたはそれを変換する:

py3>> outfile.write(plaintext.encode('utf-8'))

なぜpy2ドキュメントはfile.writeが文字列を取ると宣言したのですか? py2では、宣言の区別は重要ではありませんでした。

py2>> str==bytes         #str and bytes aliased a single hybrid class in py2
True

Py2の str-bytes クラスには、ある意味では文字列クラス、それ以外のバイト配列クラスのように動作させるメソッド/コンストラクタがあります。 file.writeに便利ではありませんか?

py2>> plaintext='my string literal'
py2>> type(plaintext)
str                              #is it a string or is it a byte array? it's both!

py2>> outfile.write(plaintext)   #can use plaintext as a byte array

なぜpy3はこのNiceシステムを壊したのですか?それは、py2では基本的な文字列関数が他の国々ではうまくいかなかったからです。 ASCII以外の文字でWordの長さを測りますか?

py2>> len('¡no')        #length of string=3, length of UTF-8 byte array=4, since with variable len encoding the non-ASCII chars = 2-6 bytes
4                       #always gives bytes.len not str.len

Py2で文字列の len を要求していると思っていた間、あなたはエンコーディングからバイト配列の長さを取得していました。そのあいまいさは二重義務クラスの根本的な問題です。どのメソッド呼び出しのどのバージョンを実装していますか?

それで良いニュースはpy3がこの問題を解決することです。それは str bytes クラスを解く。 str クラスは文字列のようなメソッドを持ち、別の bytes クラスはバイト配列メソッドを持ちます:

py3>> len('¡ok')       #string
3
py3>> len('¡ok'.encode('utf-8'))     #bytes
4

うまくいけば、これを理解しておくと問題がわかりにくくなり、移行の痛みがやや軽減されます。

9
Riaz Rizvi

Django.test.TestCase単体テストのDjangoについては、私のPython2の構文を変更しました。

def test_view(self):
    response = self.client.get(reverse('myview'))
    self.assertIn(str(self.obj.id), response.content)
    ...

Python3.decode('utf8')構文を使うには、

def test_view(self):
    response = self.client.get(reverse('myview'))
    self.assertIn(str(self.obj.id), response.content.decode('utf8'))
    ...
4
Aaron Lelevier
>>> s = bytes("s","utf-8")
>>> print(s)
b's'
>>> s = s.decode("utf-8")
>>> print(s)
s

迷惑な「b」文字を削除する場合に役立つ場合もあります。誰かが良いアイデアを得た場合は、私に提案するか、ここでいつでも編集してください。私は単なる初心者です

4