Co robi znak „b” przed dosłownym ciągiem znaków?

831

Najwyraźniej następująca poprawna składnia:

my_string = b'The string'

Chciałbym wiedzieć:

  1. Co oznacza ten bznak przed sznurkiem?
  2. Jakie są skutki korzystania z niego?
  3. Jakie są odpowiednie sytuacje, aby z niego skorzystać?

Znalazłem pokrewne pytanie tutaj na SO, ale to pytanie dotyczy PHP i stwierdza, że bsłuży do wskazania, że ​​łańcuch jest binarny, w przeciwieństwie do Unicode, który był potrzebny, aby kod był zgodny z wersją PHP <6 , podczas migracji do PHP 6. Nie sądzę, że dotyczy to Pythona.

Znalazłem tę dokumentację na stronie Pythona dotyczącą używania uznaku w tej samej składni, aby określić ciąg znaków jako Unicode. Niestety nie wspomina o znaku b nigdzie w tym dokumencie.

Poza tym, z ciekawości, czy jest więcej symboli niż bi uktóre robią inne rzeczy?

Jesse Webb
źródło

Odpowiedzi:

416

Aby zacytować dokumentację Python 2.x :

Prefiks „b” lub „B” jest ignorowany w Pythonie 2; wskazuje, że literał powinien stać się literałem bajtów w Pythonie 3 (np. gdy kod jest automatycznie konwertowany z 2to3). Przedrostek „u” lub „b” może poprzedzać przedrostek „r”.

Dokumentacja Python 3 stanowi:

Literały bajtów zawsze poprzedzone są literą „b” lub „B”; produkują instancję typu bajtów zamiast typu str. Mogą zawierać tylko znaki ASCII; bajty o wartości liczbowej 128 lub większej muszą być wyrażone znakami specjalnymi.

NPE
źródło
4
Wygląda więc na to, że Python <v3 po prostu zignoruje ten dodatkowy znak. Jak wyglądałby przypadek w v3, w którym trzeba użyć ciągu ab zamiast zwykłego ciągu?
Jesse Webb
5
@Gweebz - jeśli faktycznie wpisujesz ciąg znaków w określonym kodowaniu zamiast ze znakami unikodu (np. B '\ xff \ xfe \ xe12' zamiast '\ u32e1').
detly
7
Właściwie, jeśli już importowane unicode_literalsz __future__tego będzie „reverse” zachowanie dla tego konkretnego napisu (w Pythonie 2.x)
Romuald Brunet
34
Trochę prostsza narracja językowa wokół cytowanej dokumentacji sprawiłaby, że jest to lepsza odpowiedź IMHO
Hack-R
2
W przeciwnym razie jest odpowiedzią dla kogoś, kto już to rozumie.
Rafael Eyng
678

Python 3.x wyraźnie rozróżnia typy:

  • str= '...'literały = sekwencja znaków Unicode (UTF-16 lub UTF-32, w zależności od sposobu kompilacji Pythona)
  • bytes= b'...'literały = ciąg oktetów (liczby całkowite od 0 do 255)

Jeśli znasz Java lub C #, pomyśl o tym, strco Stringi bytesjak byte[]. Jeśli znasz SQL, pomyśl o tym strjako NVARCHARi bytesjako BINARYlub BLOB. Jeśli znasz rejestr systemu Windows, pomyśl o tym, strco REG_SZi bytesjak REG_BINARY. Jeśli znasz C (++), zapomnij o wszystkim, czego się nauczyłeś chari o łańcuchach, ponieważ ZNAK NIE JEST bajtem . Ten pomysł jest dawno przestarzały.

Używasz, strgdy chcesz reprezentować tekst.

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

Używasz go, bytesgdy chcesz reprezentować dane binarne niskiego poziomu, takie jak struktury.

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

Możesz zakodować a strdo bytesobiektu.

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

I możesz zdekodować a bytesna str.

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

Ale nie można swobodnie mieszać tych dwóch rodzajów.

>>> 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'...'Notacja jest nieco mylące w tym, że pozwala bajty 0x01-0x7F być określone za pomocą znaków ASCII zamiast liczb hex.

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

Ale muszę podkreślić, że postać nie jest bajtem .

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

W Python 2.x

Wersje Pythona w wersjach wcześniejszych niż 3.0 nie zawierały tego rodzaju rozróżnienia między tekstem a danymi binarnymi. Zamiast tego były:

  • unicode= u'...'literały = sekwencja znaków Unicode = 3.xstr
  • str= '...'literały = sekwencje pomieszanych bajtów / znaków
    • Zwykle tekst zakodowany w nieokreślonym kodowaniu.
    • Ale również używany do reprezentowania danych binarnych, takich jak dane struct.packwyjściowe.

W celu ułatwienia przejścia z wersji 2.x do 3.x b'...'literalna składnia została przeniesiona do Pythona 2.6, aby umożliwić odróżnienie ciągów binarnych (które powinny być bytesw wersji 3.x) od ciągów tekstowych (które powinny być strw postaci 3 .x). bPrefiks robi nic 2.x, ale opowiada 2to3scenariusz nie przekonwertować go na ciąg znaków Unicode w 3.x.

Tak więc, b'...'literały w Pythonie mają ten sam cel, co w PHP.

Poza tym, z ciekawości, czy jest więcej symboli niż b i u, które robią inne rzeczy?

rPrzedrostek tworzy surowy ciąg (np r'\t'jest odwrotny ukośnik + tzamiast zakładka) i potrójne cytaty '''...'''lub """..."""pozwalają literały ciągów kilka linii.

dan04
źródło
2
Dzięki! Zrozumiałem to po przeczytaniu tych zdań: „Aby ułatwić przejście z wersji 2.x do 3.x, dosłowna składnia b ... została przeniesiona do Pythona 2.6, aby umożliwić rozróżnienie ciągów binarnych (które powinny być bajtami w 3.x) z ciągów tekstowych (które powinny być ciągiem w 3.x). Prefiks b nic nie robi w 2.x, ale mówi skryptowi 2to3, aby nie konwertował go na ciąg Unicode w 3.x. ”
tommy.carstensen
4
'A' == b'A' --> FalseCheck naprawdę jasno. Reszta jest doskonała, ale do tego momentu nie zrozumiałem poprawnie, że ciąg bajtów nie
Wildcard,
12
'שלום עולם' == 'hello world'
Eli
12
Jest to o wiele bardziej jasne niż zaakceptowana odpowiedź, która po prostu cytuje dokumentację. Dokumentacja nie miała dla mnie sensu, więc zapewnianie dalszego kontekstu w dokumentacji jest niesamowite. Dzięki!
rayryeng
2
b „jakiś ciąg znaków” .decode („UTF-8”), myślę, że jest to linia, której wielu szuka
Marvin Thobejane
22

B oznacza ciąg bajtów.

Bajty to rzeczywiste dane. Ciągi znaków są abstrakcją.

Jeśli posiadasz wieloznakowy obiekt łańcuchowy i wziąłeś pojedynczy znak, będzie to ciąg znaków, który może mieć rozmiar większy niż 1 bajt, w zależności od kodowania.

Gdyby wziął 1 bajt z łańcuchem bajtów, uzyskałbyś pojedynczą 8-bitową wartość od 0-255 i może nie reprezentować pełnego znaku, jeśli te znaki z powodu kodowania miałyby> 1 bajt.

TBH Użyłbym łańcuchów, chyba że miałbym jakiś konkretny powód niskiego poziomu do używania bajtów.


źródło
16

Jeśli po stronie serwera wyślemy odpowiedź, zostanie ona wysłana w postaci typu bajtu, więc pojawi się w kliencie jako b'Response from server'

Aby pozbyć się b'....'po prostu użyj poniższego kodu:

Plik serwera:

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

Plik klienta:

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

to wydrukuje Response from server

Nani Chintha
źródło
1
To nie wyjaśnia pytania, które zadał Jesse Webb!
Chandra Kanth
Mówiłem, że bez użycia metod kodowania i dekodowania, wyjście łańcuchowe będzie poprzedzone przedrostkiem b '', ponieważ Python przyjmuje go jako typ bajtu zamiast typu string. Jeśli nie chcesz uzyskać wyjścia takiego jak b '... „skorzystaj z powyższego, to wszystko. Czego nie zrozumiałeś?
Nani Chintha,
W rzeczywistości jest to dokładnie odpowiedź na tytuł zadanego pytania: P: „Co robi b'x '?” Odp .: „To robi 'x'.encode ()” To jest dosłownie to, co robi. Pozostała część pytania chciała wiedzieć o wiele więcej, ale odpowiedź została udzielona.
Michael Erickson
10

Oto przykład, w którym brak bspowoduje zgłoszenie TypeErrorwyjątku w Pythonie 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

Dodanie bprzedrostka rozwiązałoby problem.

użytkownik3053230
źródło
9

Zmienia to w bytesliterał (lub strw wersji 2.x) i obowiązuje dla wersji 2.6+.

rPrzedrostek powoduje backslashe być „zinterpretowaną” (nie ignorowane, a różnica ma znaczenia).

Ignacio Vazquez-Abrams
źródło
To brzmi źle, zgodnie z dokumentacją cytowaną w odpowiedzi Aix; b zostanie zignorowane w wersji Python innej niż 3.
Jesse Webb
2
W strobu przypadkach będzie to 2.x, więc można powiedzieć, że jest ignorowane. To rozróżnienie ma znaczenie podczas importowania unicode_literalsz __future__modułu.
Ignacio Vazquez-Abrams,
6

Oprócz tego, co powiedzieli inni, zauważ, że pojedynczy znak w Unicode może składać się z wielu bajtów .

Sposób działania Unicode polega na tym, że wziął stary format ASCII (7-bitowy kod, który wygląda jak 0xxx xxxx) i dodał sekwencje wielobajtowe , w których wszystkie bajty zaczynają się od 1 (1xxx xxxx), aby reprezentować znaki poza ASCII, aby Unicode był odwrócony -kompatybilny z 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
źródło
2

Możesz użyć JSON, aby przekonwertować go na słownik

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

{"kluczowa wartość"}


KOLBA:

To jest przykład z kolby. Uruchom to na linii terminalu:

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

W kolbie / route.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)

{'kluczowa wartość'}

Karam Qusai
źródło