TypeError: se requiere un objeto similar a bytes, no 'str' cuando se escribe en un archivo en Python3

590

Recientemente migré a Py 3.5. Este código funcionaba correctamente en Python 2.7:

with open(fname, 'rb') as f:
    lines = [x.strip() for x in f.readlines()]

for line in lines:
    tmp = line.strip().lower()
    if 'some-pattern' in tmp: continue
    # ... code

Después de actualizar a 3.5, obtengo el:

TypeError: a bytes-like object is required, not 'str'

error en la última línea (el código de búsqueda del patrón).

Intenté usar la .decode()función a cada lado de la declaración, también probé:

if tmp.find('some-pattern') != -1: continue

- en vano.

Pude resolver casi todos los problemas 2: 3 rápidamente, pero esta pequeña declaración me está molestando.

masroore
fuente
11
¿Por qué abre el archivo en modo binario pero lo trata como texto?
Martijn Pieters
44
@MartijnPieters gracias por detectar el modo abierto de archivo! Cambiarlo al modo de texto resolvió el problema ... aunque el código había funcionado de manera confiable en Py2k durante muchos años ...
masroore
10
También me encuentro con esto cuando tengo una solicitud result = requests.gety lo intento x = result.content.split("\n"). Estoy un poco confundido por el mensaje de error porque parece implicar que result.contentes una cadena y .split()requiere un objeto de tipo bytes ... ?? ("se requiere un objeto similar a bytes, no 'str"') ..

Respuestas:

553

Abriste el archivo en modo binario:

with open(fname, 'rb') as f:

Esto significa que todos los datos leídos del archivo se devuelven como bytesobjetos, no str. Entonces no puede usar una cadena en una prueba de contención:

if 'some-pattern' in tmp: continue

Tendría que usar un bytesobjeto para probar en su tmplugar:

if b'some-pattern' in tmp: continue

o abra el archivo como un archivo de texto reemplazando el 'rb'modo con 'r'.

Martijn Pieters
fuente
12
Si echa un vistazo a los diversos documentos a los que se ha vinculado ppl, verá que todo "funcionó" en Py2 porque las cadenas predeterminadas eran bytes, mientras que en Py3, las cadenas predeterminadas son Unicode, lo que significa que en cualquier momento que esté haciendo E / S, especialmente redes, las cadenas de bytes son el estándar, por lo que debe aprender a mover cadenas Unicode y bytes (en / decode). Para archivos, ahora tenemos "r" vs. "rb" (y para 'w' y 'a') para ayudar a diferenciar.
wescpy
3
@wescpy: Pitón 2 tiene 'r'vs 'rb' demasiado , el cambio entre las conductas de archivos binarios y de texto (como los saltos de línea que traducen y en ciertas plataformas, cómo se trata el marcador EOF). Que la iobiblioteca (que proporciona la funcionalidad de E / S predeterminada en Python 3 pero también disponible en Python 2) ahora también decodifica archivos de texto de forma predeterminada es el cambio real.
Martijn Pieters
2
@ MartijnPieters: Sí, de acuerdo. En 2.x, solo utilicé el 'b'indicador cuando tuve que trabajar con archivos binarios en DOS / Windows (ya que binario es el valor predeterminado de POSIX). Es bueno que haya un doble propósito cuando se usa ioen 3.x para el acceso a archivos.
wescpy
209

Puedes codificar tu cadena usando .encode()

Ejemplo:

'Hello World'.encode()
theofpa
fuente
48

Como ya se mencionó, está leyendo el archivo en modo binario y luego está creando una lista de bytes. En tu seguimiento por bucle , está comparando cadena a bytes y ahí es donde falla el código.

La decodificación de los bytes mientras se agrega a la lista debería funcionar. El código modificado debería tener el siguiente aspecto:

with open(fname, 'rb') as f:
    lines = [x.decode('utf8').strip() for x in f.readlines()]

El tipo de bytes se introdujo en Python 3 y es por eso que su código funcionó en Python 2. En Python 2 no había ningún tipo de datos para bytes:

>>> s=bytes('hello')
>>> type(s)
<type 'str'>
Suresh
fuente
25

Tienes que cambiar de wb a w:

def __init__(self):
    self.myCsv = csv.writer(open('Item.csv', 'wb')) 
    self.myCsv.writerow(['title', 'link'])

a

def __init__(self):
    self.myCsv = csv.writer(open('Item.csv', 'w'))
    self.myCsv.writerow(['title', 'link'])

Después de cambiar esto, el error desaparece, pero no puede escribir en el archivo (en mi caso). Entonces, después de todo, ¿no tengo una respuesta?

Fuente: Cómo eliminar ^ M

Cambiar a 'rb' me trae el otro error: io.UnsupportedOperation: write

meck373
fuente
15

para este pequeño ejemplo: zócalo de importación

mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysock.connect(('www.py4inf.com', 80))
mysock.send(**b**'GET http://www.py4inf.com/code/romeo.txt HTTP/1.0\n\n')

while True:
    data = mysock.recv(512)
    if ( len(data) < 1 ) :
        break
    print (data);

mysock.close()

agregar la "b" antes de 'GET http://www.py4inf.com/code/romeo.txt HTTP / 1.0 \ n \ n' resolvió mi problema

inicio
fuente
11

Use la función encode () junto con el valor String codificado en una comilla simple.

Ex:

file.write(answers[i] + '\n'.encode())

O

line.split(' +++$+++ '.encode())
Shiv Buyya
fuente
8

Abriste el archivo en modo binario:

El siguiente código arrojará un TypeError: se requiere un objeto de tipo bytes, no 'str'.

for line in lines:
    print(type(line))# <class 'bytes'>
    if 'substring' in line:
       print('success')

El siguiente código funcionará: debe usar la función decode ():

for line in lines:
    line = line.decode()
    print(type(line))# <class 'str'>
    if 'substring' in line:
       print('success')
Matan Hugi
fuente
1

Recibí este error cuando intentaba convertir un char (o cadena) bytes, el código era algo así con Python 2.7:

# -*- coding: utf-8 -*-
print( bytes('ò') )

Este es el camino de Python 2.7 cuando se trata de caracteres unicode.

Esto no funcionará con Python 3.6, ya que bytesrequiere un argumento adicional para la codificación, pero esto puede ser un poco complicado, ya que una codificación diferente puede generar resultados diferentes:

print( bytes('ò', 'iso_8859_1') ) # prints: b'\xf2'
print( bytes('ò', 'utf-8') ) # prints: b'\xc3\xb2'

En mi caso tuve que usar iso_8859_1 al codificar bytes para resolver el problema.

Espero que esto ayude a alguien.

Ibrahim.H
fuente