TypeError: требуется байтоподобный объект, а не 'str' при записи в файл в Python3

590

Я совсем недавно перешел на Py 3.5. Этот код работал правильно в 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

После обновления до 3.5 я получаю:

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

ошибка в последней строке (код поиска шаблона).

Я попытался использовать .decode()функцию с обеих сторон оператора, а также попытался:

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

- но безрезультатно.

Мне удалось быстро решить почти все проблемы 2: 3, но это небольшое утверждение меня беспокоит.

masroore
источник
11
Почему вы открываете файл в двоичном режиме, но рассматриваете его как текст?
Мартин Питерс
4
@MartijnPieters спасибо за обнаружение режима открытия файла! Переход на текстовый режим решил проблему ... хотя код работал в Py2k надежно много лет ...
masroore
10
Я сталкиваюсь с этим тоже, где у меня есть запросы, result = requests.getи я пытаюсь x = result.content.split("\n"). Я немного сбит с толку сообщением об ошибке, потому что оно, похоже, подразумевает, что result.contentэто строка и .split()требует объект, похожий на байты .. ?? («Требуется подобный байту объект, а не« str »») ..

Ответы:

553

Вы открыли файл в двоичном режиме:

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

Это означает, что все данные, прочитанные из файла, возвращаются как bytesобъекты, а не str. Затем вы не можете использовать строку в тесте содержания:

if 'some-pattern' in tmp: continue

Вместо этого вам придется использовать bytesобъект для проверки tmp:

if b'some-pattern' in tmp: continue

или вместо этого откройте файл как текстовый файл, заменив 'rb'режим на 'r'.

Мартейн Питерс
источник
12
Если вы посмотрите на различные документы, на которые ссылается ppl, вы увидите, что в Py2 все «работало», потому что строки по умолчанию были байтами, тогда как в Py3 строки по умолчанию были Unicode, то есть каждый раз, когда вы выполняете ввод / вывод, особенно сеть, байтовые строки являются стандартом, поэтому вы должны научиться перемещать ч / б строки Юникода и байты (en / decode). Для файлов у нас теперь есть «r» против «rb» (и для «w» & «a»), чтобы помочь дифференцировать.
Wescpy
3
@wescpy: в Python 2 тоже есть 'r'vs , переключение между поведением двоичных и текстовых файлов (например, перевод новых строк и на определенных платформах, как обрабатывается маркер EOF). То, что библиотека (обеспечивающая функциональность ввода-вывода по умолчанию в Python 3, но также доступная в Python 2) теперь также декодирует текстовые файлы по умолчанию, является реальным изменением. 'rb' io
Мартин Питерс
2
@MartijnPieters: Да, согласился. В версии 2.x я использовал этот 'b'флаг только при работе с двоичными файлами в DOS / Windows (так как двоичный файл используется по умолчанию в POSIX). Хорошо, что использование io3.x для доступа к файлам имеет двойную цель .
Wescpy
209

Вы можете закодировать вашу строку с помощью .encode()

Пример:

'Hello World'.encode()
theofpa
источник
48

Как уже упоминалось, вы читаете файл в двоичном режиме, а затем создаете список байтов. В последующем цикле for вы сравниваете строку с байтами, и именно в этом коде происходит сбой.

Декодирование байтов при добавлении в список должно работать. Измененный код должен выглядеть следующим образом:

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

Тип байтов был введен в Python 3, и поэтому ваш код работал в Python 2. В Python 2 не было типа данных для байтов:

>>> s=bytes('hello')
>>> type(s)
<type 'str'>
Суреш
источник
25

Вы должны изменить с wb на w:

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

в

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

После изменения ошибка исчезает, но вы не можете записать в файл (в моем случае). Так в конце концов, у меня нет ответа?

Источник: Как убрать ^ M

Изменение на 'rb' приносит мне другую ошибку: io.UnsupportedOperation: write

meck373
источник
15

для этого небольшого примера: импортное гнездо

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

добавление «b» до того, как «GET» http://www.py4inf.com/code/romeo.txt HTTP / 1.0 \ n \ n 'решило мою проблему

стартер
источник
11

Используйте функцию encode () вместе с жестко закодированным значением String, указанным в одиночной кавычке.

Пример:

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

ИЛИ

line.split(' +++$+++ '.encode())
Шив Буя
источник
8

Вы открыли файл в двоичном режиме:

Следующий код выдаст ошибку TypeError: требуется объект, похожий на байты, а не 'str'.

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

Следующий код будет работать - вы должны использовать функцию decode ():

for line in lines:
    line = line.decode()
    print(type(line))# <class 'str'>
    if 'substring' in line:
       print('success')
Матан Хуги
источник
4

почему бы не попробовать открыть свой файл как текст?

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

Кроме того, здесь есть ссылка на python 3.x на официальной странице: https://docs.python.org/3/library/io.html А это открытая функция: https://docs.python.org/3 /library/functions.html#open

Если вы действительно пытаетесь обработать его как двоичный файл, подумайте о кодировании вашей строки.

Фернандо Д Хайме
источник
1

Я получил эту ошибку, когда пытался преобразовать символ (или строку) bytesв код, что-то вроде этого с Python 2.7:

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

Это способ Python 2.7 при работе с символами Юникода.

Это не будет работать с Python 3.6, так как bytesтребует дополнительного аргумента для кодирования, но это может быть немного сложно, так как разные кодировки могут привести к разным результатам:

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

В моем случае мне пришлось использовать iso_8859_1при кодировании байтов, чтобы решить проблему.

Надеюсь, это кому-нибудь поможет.

Ibrahim.H
источник