Que fait le caractère «b» devant un littéral de chaîne?

832

Apparemment, ce qui suit est la syntaxe valide:

my_string = b'The string'

J'aimerais savoir:

  1. Que signifie ce bcaractère devant la chaîne?
  2. Quels sont les effets de son utilisation?
  3. Quelles sont les situations appropriées pour l'utiliser?

J'ai trouvé une question connexe ici sur SO, mais cette question concerne PHP, et elle indique que le best utilisé pour indiquer que la chaîne est binaire, par opposition à Unicode, qui était nécessaire pour que le code soit compatible avec la version de PHP <6 , lors de la migration vers PHP 6. Je ne pense pas que cela s'applique à Python.

J'ai trouvé cette documentation sur le site Python sur l'utilisation d'un ucaractère dans la même syntaxe pour spécifier une chaîne comme Unicode. Malheureusement, il ne mentionne le caractère b nulle part dans ce document.

Aussi, juste par curiosité, y a-t-il plus de symboles que le bet uqui font autre chose?

Jesse Webb
la source

Réponses:

417

Pour citer la documentation Python 2.x :

Un préfixe de «b» ou «B» est ignoré dans Python 2; cela indique que le littéral devrait devenir un littéral d'octets en Python 3 (par exemple lorsque le code est automatiquement converti avec 2to3). Un préfixe «u» ou «b» peut être suivi d'un préfixe «r».

La documentation Python 3 indique:

Les littéraux d'octets sont toujours préfixés par «b» ou «B»; ils produisent une instance du type bytes au lieu du type str. Ils ne peuvent contenir que des caractères ASCII; les octets d'une valeur numérique de 128 ou plus doivent être exprimés avec des échappements.

NPE
la source
4
Il semble donc que Python <v3 ignorera simplement ce caractère supplémentaire. Quel serait un cas dans la v3 où vous auriez besoin d'utiliser une chaîne ab au lieu d'une simple chaîne régulière?
Jesse Webb
5
@Gweebz - si vous tapez en fait une chaîne dans un encodage particulier au lieu d'échappements Unicode (par exemple b '\ xff \ xfe \ xe12' au lieu de '\ u32e1').
detly
7
En fait, si vous avez importé unicode_literalsdepuis __future__, cela "inversera" le comportement de cette chaîne particulière (en Python 2.x)
Romuald Brunet
34
Un récit un peu plus clair sur la documentation citée en ferait une meilleure réponse IMHO
Hack-R
2
Sinon, c'est une réponse pour quelqu'un qui le comprend déjà.
Rafael Eyng
681

Python 3.x fait une distinction claire entre les types:

  • str= '...'littéraux = une séquence de caractères Unicode (UTF-16 ou UTF-32, selon la façon dont Python a été compilé)
  • bytes= b'...'littéraux = une séquence d'octets (entiers compris entre 0 et 255)

Si vous êtes familier avec Java ou C #, pensez au strfur Stringet à bytesmesure byte[]. Si vous connaissez SQL, pensez à stras NVARCHARet bytesas BINARYou BLOB. Si vous êtes familier avec le registre Windows, pensez au strfur REG_SZet à bytesmesure REG_BINARY. Si vous êtes familier avec C (++), oubliez tout ce que vous avez appris charet les chaînes, car UN PERSONNAGE N'EST PAS UN OCTET . Cette idée est depuis longtemps obsolète.

Vous utilisez strlorsque vous souhaitez représenter du texte.

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

Vous utilisez byteslorsque vous souhaitez représenter des données binaires de bas niveau comme des structures.

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

Vous pouvez encoder un stren un bytesobjet.

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

Et vous pouvez décoder un bytesen un str.

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

Mais vous ne pouvez pas mélanger librement les deux types.

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

La b'...'notation est quelque peu déroutante en ce qu'elle permet de spécifier les octets 0x01-0x7F avec des caractères ASCII au lieu de nombres hexadécimaux.

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

Mais je dois souligner qu'un caractère n'est pas un octet .

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

En Python 2.x

Les versions pré-3.0 de Python n'avaient pas ce genre de distinction entre le texte et les données binaires. Au lieu de cela, il y avait:

  • unicode= u'...'littéraux = séquence de caractères Unicode = 3.xstr
  • str= '...'littéraux = séquences d'octets / caractères confondus
    • Généralement du texte, codé dans un codage non spécifié.
    • Mais également utilisé pour représenter des données binaires comme la struct.packsortie.

Afin de faciliter la transition de 2.x vers 3.x, la b'...'syntaxe littérale a été rétroportée vers Python 2.6, afin de permettre de distinguer les chaînes binaires (qui devraient être bytesen 3.x) des chaînes de texte (qui devraient être stren 3 .X). Le bpréfixe ne fait rien dans 2.x, mais indique au 2to3script de ne pas le convertir en chaîne Unicode dans 3.x.

Alors oui, les b'...'littéraux en Python ont le même objectif qu'en PHP.

Aussi, juste par curiosité, y a-t-il plus de symboles que le b et le u qui font autre chose?

Le rpréfixe crée une chaîne brute (par exemple, r'\t'est une barre oblique inversée + tau lieu d'un onglet), et des guillemets triples '''...'''ou """..."""autorisent des littéraux de chaîne multi-lignes.

dan04
la source
2
Merci! Je l'ai compris après avoir lu ces phrases: "Afin de faciliter la transition 2.x vers 3.x, la syntaxe littérale b '...' a été rétroportée vers Python 2.6, afin de permettre de distinguer les chaînes binaires (qui devraient be bytes in 3.x) from string text (which should be str in 3.x). Le préfixe b ne fait rien en 2.x, mais indique au script 2to3 de ne pas le convertir en chaîne Unicode en 3.x. "
tommy.carstensen
4
Le 'A' == b'A' --> Falsechèque le rend vraiment clair. Le reste est excellent, mais jusqu'à ce moment-là, je n'avais pas bien compris qu'une chaîne d'octets n'était pas vraiment du texte.
Wildcard
12
'שלום עולם' == 'hello world'
Eli
13
C'est beaucoup plus clair que la réponse acceptée qui ne fait que citer la documentation. Pour moi, la documentation n'avait aucun sens, donc fournir plus de contexte dans la documentation est génial. Merci!
rayryeng
3
b "une chaîne" .decode ('UTF-8'), je crois que c'est la ligne que beaucoup recherchent
Marvin Thobejane
23

Le b désigne une chaîne d'octets.

Les octets sont les données réelles. Les cordes sont une abstraction.

Si vous aviez un objet chaîne à plusieurs caractères et que vous preniez un seul caractère, ce serait une chaîne, et sa taille pourrait être supérieure à 1 octet, selon l'encodage.

Si vous preniez 1 octet avec une chaîne d'octets, vous obtiendriez une seule valeur de 8 bits de 0 à 255 et elle pourrait ne pas représenter un caractère complet si ces caractères dus au codage étaient> 1 octet.

TBH J'utiliserais des chaînes sauf si j'avais une raison spécifique de bas niveau d'utiliser des octets.


la source
16

Du côté serveur, si nous envoyons une réponse, elle sera envoyée sous la forme d'un type d'octet, elle apparaîtra donc dans le client comme b'Response from server'

Pour vous débarrasser de b'....'simplement utiliser le code ci-dessous:

Fichier serveur:

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

Fichier client:

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

puis il imprimera Response from server

Nani Chintha
la source
1
Cela n'explique pas la question que Jesse Webb a posée!
Chandra Kanth
Je disais que sans utiliser les méthodes d'encodage et de décodage, la sortie de chaîne sera préfixée avec b '' car python le prendra comme type d'octet au lieu de type de chaîne.Si vous ne voulez pas obtenir une sortie comme b '... 'utilisez ce qui précède. Qu'est-ce que vous n'avez pas compris?
Nani Chintha
En fait, c'est exactement la réponse au titre de la question qui a été posée: Q: "Que fait b'x '?" R: "Il fait 'x'.encode ()" C'est littéralement ce qu'il fait. Le reste de la question voulait en savoir beaucoup plus que cela, mais le titre est répondu.
Michael Erickson
10

Voici un exemple où l'absence de blève une TypeErrorexception dans 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

L'ajout d'un bpréfixe résoudrait le problème.

user3053230
la source
9

Il le transforme en byteslittéral (ou stren 2.x), et est valide pour 2.6+.

Le rpréfixe fait que les barres obliques inverses sont "non interprétées" (non ignorées, et la différence est importante).

Ignacio Vazquez-Abrams
la source
Cela semble faux selon la documentation citée dans la réponse d'Aix; le b sera ignoré dans la version Python autre que 3.
Jesse Webb
2
Ce sera strdans un 2.x dans les deux cas, donc on pourrait dire qu'il est ignoré. La distinction est importante lorsque vous importez à unicode_literalspartir du __future__module.
Ignacio Vazquez-Abrams
6

En plus de ce que d'autres ont dit, notez qu'un seul caractère en unicode peut être composé de plusieurs octets .

La façon dont fonctionne unicode est qu'il a fallu l'ancien format ASCII (code 7 bits qui ressemble à 0xxx xxxx) et ajouté des séquences multi-octets où tous les octets commencent par 1 (1xxx xxxx) pour représenter les caractères au-delà de l'ASCII afin que Unicode soit en arrière -compatible avec 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
la source
2

Vous pouvez utiliser JSON pour le convertir en dictionnaire

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

{"valeur clé"}


BALLON:

Ceci est un exemple de flacon. Exécutez ceci sur la ligne du terminal:

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

Dans le flacon / routes.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)

{'valeur clé'}

Karam Qusai
la source