"TypeError: требуется объект, похожий на bytes, а не 'str' при обработке содержимого файла в Python 3"
Я недавно мигрировал на Python 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
# ... код
Однако в Python 3.5 на строке if 'some-pattern' in tmp: continue
я получаю ошибку:
TypeError: a bytes-like object is required, not 'str'
Я не смог решить проблему, использовав .decode()
с обеих сторон оператора in
, а также не помогло применение следующего кода:
if tmp.find('some-pattern') != -1: continue
Что не так, и как мне это исправить?
5 ответ(ов)
Вы открыли файл в бинарном режиме:
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'
.
Вы можете закодировать вашу строку, используя метод .encode()
.
Пример:
'Hello World'.encode()
Как описано в сообщении об ошибке, чтобы записать строку в файл, вам необходимо сначала закодировать её в объект, подобный байтам, и метод encode()
преобразует её в байтовую строку.
Как уже было упомянуто, вы открываете файл в бинарном режиме и затем создаете список байтов. В вашем последующем цикле for вы сравниваете строку с байтами, из-за чего код не работает.
Декодирование байтов во время добавления в список должно решить проблему. Измененный код будет выглядеть следующим образом:
with open(fname, 'rb') as f:
lines = [x.decode('utf8').strip() for x in f.readlines()]
Тип bytes
был введен в Python 3, и именно поэтому ваш код работал в Python 2. В Python 2 не существовало типа данных для байтов:
>>> s=bytes('hello')
>>> type(s)
<type 'str'>
Вам нужно использовать функцию encode()
вместе с заданной строкой, заключённой в одинарные кавычки. Вот примеры использования этой функции:
Пример 1:
file.write(answers[i].encode() + b'\n')
В данном случае строка answers[i]
сначала кодируется в байты с помощью encode()
, а затем добавляется символ новой строки в байтовом формате с помощью префикса b
.
Пример 2:
line.split(b' +++$+++ ')
Здесь мы вызываем метод split()
на строке line
, разделитель также заключён в байтовый литерал с префиксом b
. Это позволит корректно разбирать строку, используя кодировку байтов.
Вам нужно помнить, что когда файл открыт в бинарном режиме, каждая строка будет представлять собой объект типа bytes
, а не str
. Это означает, что при попытке выполнить операцию проверки на наличие подстроки, вы столкнетесь с ошибкой TypeError: a bytes-like object is required, not 'str'
.
Вот пример кода, который приведет к этой ошибке:
for line in lines:
print(type(line)) # <class 'bytes'>
if 'substring' in line: # Здесь возникнет ошибка
print('success')
Чтобы избежать этой ошибки, вам нужно декодировать объект bytes
в строку с помощью метода decode()
. Вот исправленный код:
for line in lines:
line = line.decode() # Декодируем строку из bytes в str
print(type(line)) # <class 'str'>
if 'substring' in line: # Теперь это сработает правильно
print('success')
Таким образом, после декодирования вы сможете успешно проверять наличие подстроки и избежать ошибок.
Преобразование байтов в строку в Python 3
Как читать файл построчно в список?
Есть ли в Python метод подстроки 'contains' для строк?
Объединение двух столбцов текста в DataFrame pandas
Вывод строки в текстовый файл