web-dev-qa-db-fra.com

TypeError: 'str' ne supporte pas l'interface de tampon

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) 

Le code python ci-dessus me donne l'erreur suivante:

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
262
Future King

Si vous utilisez Python3x, alors string n'est pas du même type que pour Python 2.x, vous devez le convertir en octets (l'encoder).

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

De même, n'utilisez pas de noms de variables tels que string ou file, car il s'agit de noms de module ou de fonction.

EDIT @Tom

Oui, le texte non-ASCII est également compressé/décompressé. J'utilise des lettres polonaises avec le codage 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)
292
Michał Niklas

Il existe une solution plus facile à ce problème.

Vous devez simplement ajouter un t au mode pour qu'il devienne wt. Ainsi, Python ouvre le fichier en tant que fichier texte et non binaire. Ensuite, tout fonctionnera.

Le programme complet devient ceci:

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)
96
user1175849

Vous ne pouvez pas sérialiser une chaîne Python 3 en octets sans une conversion explicite en un codage.

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

est peut-être ce que vous voulez. Cela fonctionne également pour python 2.x et 3.x.

42
Andreas Jung

Pour Python 3.x, vous pouvez convertir votre texte en octets bruts via:

bytes("my data", "encoding")

Par exemple:

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

L'objet retourné fonctionnera avec outfile.write.

28
Skurmedel

Ce problème se produit généralement lors du passage de py2 à py3. Dans py2, plaintext est à la fois une chaîne et un tableau type. Dans py3, plaintext n’est qu’une chaîne et la méthode outfile.write() prend en réalité un . tableau d'octets lorsque outfile est ouvert en mode binaire, une exception est donc déclenchée. Modifiez l'entrée en plaintext.encode('utf-8') pour résoudre le problème. Continuez à lire si cela vous dérange.

Dans py2, le déclaration de file.write donnait l'impression que vous aviez passé une chaîne: file.write(str). En fait, vous passiez dans un tableau d'octets, vous auriez dû lire la déclaration comme ceci: file.write(bytes). Si vous le lisez ainsi, le problème est simple, file.write(bytes) a besoin d'un type octets et en py3 pour obtenir octets sur un str vous le convertissez:

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

Pourquoi les documents py2 ont-ils déclaré file.write pris une chaîne? Dans py2, la distinction de déclaration importait peu car:

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

La classe str-bytes de py2 a des méthodes/constructeurs qui la font se comporter comme une classe de chaînes d'une certaine manière et une classe de tableau d'octets d'autres. Pratique pour file.write n'est-ce pas?

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

Pourquoi py3 a-t-il cassé ce système de Nice? Eh bien, car dans py2, les fonctions de base des chaînes ne fonctionnaient pas pour le reste du monde. Mesurer la longueur d'un mot avec un caractère non-ASCII?

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

Pendant tout ce temps, vous pensiez demander le len d'une chaîne en py2, vous obteniez la longueur du tableau d'octets à partir de l'encodage. Cette ambiguïté est le problème fondamental des classes à double tâche. Quelle version d'un appel de méthode implémentez-vous?

La bonne nouvelle est que py3 résout ce problème. Il démêle les classes str et octets . La classe str a des méthodes de type chaîne, la classe séparée octets a méthodes de tableau d'octets:

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

J'espère que le fait de savoir que cela aide à résoudre le problème et rend la douleur liée à la migration un peu plus facile à supporter.

9
Riaz Rizvi

Pour Django dans le test d'unité Django.test.TestCase, j'ai modifié ma syntaxe Python2:

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

Pour utiliser la syntaxe Python.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

Bien si utile pour vous en cas de suppression du caractère 'b' agaçant. Si quelqu'un a une meilleure idée s'il vous plaît suggérez-moi ou n'hésitez pas à me modifier à tout moment ici.Je suis juste un débutant

4
Tapasit Suesasiton