Что символ «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 или более должны быть выражены с помощью экранирования.

NPE
источник
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вместо вкладки), а также тройные кавычки '''...'''или """..."""позволяют многострочным строковые литералы.

dan04
источник
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префикса решит проблему.

user3053230
источник
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
xjcl
источник
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)

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

Карам Кусай
источник