Что символ «b» делает перед строковым литералом?


833

Видимо, следующий допустимый синтаксис:

my_string = b'The string'

Я бы хотел знать:

  1. Что означает этот bсимвол перед строкой?
  2. Каковы последствия его использования?
  3. Каковы подходящие ситуации, чтобы использовать это?

Я нашел связанный вопрос прямо здесь, на SO, но этот вопрос касается PHP, и в нем говорится, что bон используется, чтобы указать, что строка является двоичной, в отличие от Unicode, который был необходим для совместимости кода из версии PHP <6 , при переходе на PHP 6. Я не думаю, что это относится к Python.

Я нашел эту документацию на сайте Python об использовании uсимвола в том же синтаксисе для указания строки как Unicode. К сожалению, в этом документе нигде не упоминается символ b .

Кроме того, просто из любопытства, есть ли больше символов, чем bи uкоторые делают другие вещи?

Ответы:


418

Цитировать документацию по Python 2.x :

Префикс 'b' или 'B' игнорируется в Python 2; это указывает на то, что литерал должен стать байтовым литералом в Python 3 (например, когда код автоматически конвертируется с 2to3). За префиксом «u» или «b» может следовать префикс «r».

Документация Python 3 гласит:

Байтовые литералы всегда начинаются с префикса 'b' или 'B'; они производят экземпляр типа байтов вместо типа str. Они могут содержать только символы ASCII; байты с числовым значением 128 или более должны быть выражены с помощью экранирования.


4
Похоже, что Python <v3 просто проигнорирует этот дополнительный символ. Что будет в случае v3, когда вам нужно будет использовать строку ab, а не обычную строку?
— Джесси Уэбб

5
@Gweebz - если вы на самом деле печатаете строку в определенной кодировке вместо экранированных символов Юникод (например, b '\ xff \ xfe \ xe12' вместо '\ u32e1').
— детально

7
На самом деле, если вы импортировали unicode_literalsиз __future__, это «обратное» поведение для этой конкретной строки (в Python 2.x)
— Romuald Brunet

35
Немного более простой формулировки на основе цитируемой документации сделало бы этот ответ лучше ИМХО
— Hack-R

2
В противном случае, это ответ для кого-то, кто уже понимает это.
— Рафаэль Эйнг

681

Python 3.x проводит четкое различие между типами:

  • str= '...'литералы = последовательность символов Unicode (UTF-16 или UTF-32, в зависимости от того, как Python был скомпилирован)
  • bytes= b'...'литералы = последовательность октетов (целые числа от 0 до 255)

Если вы знакомы с Java или C #, подумайте, strкак Stringи bytesкак byte[]. Если вы знакомы с SQL, подумайте strкак NVARCHARи bytesкак BINARYили BLOB. Если вы знакомы с реестром Windows, подумайте strкак REG_SZи bytesкак REG_BINARY. Если вы знакомы с C (++), то забудьте все, что вы узнали, charи строки, потому что CHARACTER НЕ БАЙТ . Эта идея давно устарела.

Вы используете, strкогда вы хотите представить текст.

print('שלום עולם')

Вы используете, bytesкогда хотите представить низкоуровневые двоичные данные, такие как структуры.

NaN = struct.unpack('>d', b'\xff\xf8\x00\x00\x00\x00\x00\x00')[0]

Вы можете кодироватьstr к bytesобъекту.

>>> '\uFEFF'.encode('UTF-8')
b'\xef\xbb\xbf'

И вы можете расшифровать bytesв str.

>>> b'\xE2\x82\xAC'.decode('UTF-8')
'€'

Но вы не можете свободно смешивать два типа.

>>> b'\xEF\xBB\xBF' + 'Text with a UTF-8 BOM'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't concat bytes to str

b'...'Нотация несколько запутанным в том , что она позволяет байты 0x01-0x7F должны быть указаны с ASCII - символов вместо шестнадцатеричных цифр.

>>> b'A' == b'\x41'
True

Но я должен подчеркнуть, что символ не байт .

>>> 'A' == b'A'
False

В Python 2.x

В версиях Python до 3.0 не было такого различия между текстовыми и двоичными данными. Вместо этого было:

  • unicode= u'...'литералы = последовательность символов Unicode = 3.xstr
  • str= '...'литералы = последовательности смешанных байтов / символов
    • Обычно текст, закодированный в какой-то неуказанной кодировке.
    • Но также используется для представления двоичных данных, таких как struct.packвывод.

Чтобы облегчить переход с 2.x на 3.x, b'...'буквальный синтаксис был перенесен в Python 2.6, чтобы позволить отличать двоичные строки (которые должны быть bytesв 3.x) от текстовых строк (которые должны быть strв 3 .Икс). bПриставка ничего не делает в 2.x, но говорит 2to3сценарий не преобразовать его в строку Unicode в 3.x.

Так что да, b'...'литералы в Python имеют ту же цель, что и в PHP.

Кроме того, просто из любопытства, есть ли больше символов, чем b и u, которые делают другие вещи?

rПрефикс создает строку (например, r'\t'является обратным слэшем + tвместо вкладки), а также тройные кавычки '''...'''или """..."""позволяют многострочным строковые литералы.


2
Спасибо! Я понял это после прочтения этих предложений: «Для облегчения перехода с 2.x на 3.x буквальный синтаксис b '...' был перенесен в Python 2.6, чтобы позволить различать двоичные строки (которые должны быть байтами в 3.x) из текстовых строк (которые должны быть str в 3.x). Префикс b ничего не делает в 2.x, но говорит сценарию 2to3 не преобразовывать его в строку Unicode в 3.x. "
— tommy.carstensen

4
'A' == b'A' --> FalseПроверка действительно делает это ясно. В остальном это отлично, но до этого момента я не понимал, что строка байтов на самом деле не
— Уайлдкарт

12
'שלום עולם' == 'hello world'
— Илай

13
Это гораздо яснее, чем принятый ответ, который просто цитирует документацию. Документация для меня не имеет смысла, поэтому предоставление дополнительного контекста в документации - это круто. Спасибо!
— Rayryeng

3
b "некоторая строка" .decode ('UTF-8'), я полагаю, что это линия, которую многие ищут
— Марвин Тобеджейн

23

B обозначает байтовую строку.

Байты являются фактическими данными. Строки - это абстракция.

Если у вас был многосимвольный строковый объект и вы взяли один символ, это будет строка, и ее размер может быть больше 1 байта в зависимости от кодировки.

Если взять 1 байт со строкой байтов, вы получите одно 8-битное значение от 0 до 255, и оно может не представлять полный символ, если эти символы из-за кодировки были> 1 байта.

TBH Я бы использовал строки, если у меня не было какой-то конкретной причины низкого уровня для использования байтов.


16

Со стороны сервера, если мы отправим какой-либо ответ, он будет отправлен в виде байтового типа, поэтому он будет отображаться в клиенте как b'Response from server'

Для того, чтобы избавиться от b'....'просто используйте ниже код:

Файл сервера:

stri="Response from server"    
c.send(stri.encode())

Клиентский файл:

print(s.recv(1024).decode())

тогда он напечатает Response from server


1
Это не объясняет вопрос, который задал Джесси Уэбб!
— Чандра Кант

Я говорил, что без использования методов кодирования и декодирования вывод строки будет иметь префикс b '', так как python воспринимает его как тип байта, а не как строковый тип. Если вы не хотите получать вывод типа b '... «Используйте выше, вот и все. Что вы не поняли?
— Нани Чинта

На самом деле это именно тот ответ на заголовок вопроса, который был задан: Q: "Что делает B'X '?" A: "Это делает 'x'.encode ()" Это буквально то, что он делает. Остальная часть вопроса хотела знать намного больше, чем это, но на заголовок ответили.
— Майкл Эриксон

10

Вот пример, где отсутствие bбросило бы TypeErrorисключение в Python 3.x

>>> f=open("new", "wb")
>>> f.write("Hello Python!")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' does not support the buffer interface

Добавление bпрефикса решит проблему.


9

Он превращает его в bytesлитерал (или strв 2.x) и действителен для 2.6+.

rПрефикс вызывает обратные косые быть «необработанном» (не игнорируется, а разница делает дело).


Это звучит неправильно в соответствии с документацией, приведенной в ответе AIX; b будет игнорироваться в версии Python, отличной от 3.
— Джесси Уэбб

2
Это будет strверсия 2.x в любом случае, поэтому можно сказать, что она игнорируется. Различие имеет значение при импорте unicode_literalsиз __future__модуля.
— Игнасио Васкес-Абрамс

6

В дополнение к тому, что сказали другие, обратите внимание, что один символ в юникоде может состоять из нескольких байтов .

Юникод работает так, что он взял старый формат ASCII (7-битный код, который выглядит как 0xxx xxxx) и добавил многобайтовые последовательности, где все байты начинаются с 1 (1xxx xxxx), чтобы представить символы за пределами ASCII, чтобы Юникод был обратным -совместимый с ASCII.

>>> len('Öl')  # German word for 'oil' with 2 characters
2
>>> 'Öl'.encode('UTF-8')  # convert str to bytes 
b'\xc3\x96l'
>>> len('Öl'.encode('UTF-8'))  # 3 bytes encode 2 characters !
3

2

Вы можете использовать JSON, чтобы преобразовать его в словарь

import json
data = b'{"key":"value"}'
print(json.loads(data))

{ "Ключ": "значение"}


ФЛЯГА:

Это пример из колбы. Запустите это на терминальной линии:

import requests
requests.post(url='http://localhost(example)/',json={'key':'value'})

В фляге / rout.py

@app.route('/', methods=['POST'])
def api_script_add():
    print(request.data) # --> b'{"hi":"Hello"}'
    print(json.loads(request.data))
return json.loads(request.data)

{ 'Ключ': 'значение'}

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.