อักขระ 'b' ทำอะไรต่อหน้าตัวอักษรสตริง?


831

เห็นได้ชัดว่าต่อไปนี้เป็นไวยากรณ์ที่ถูกต้อง:

my_string = b'The string'

ผมอยากจะรู้ว่า:

  1. bอักขระนี้ต่อหน้าสตริงหมายถึงอะไร
  2. การใช้งานมีผลกระทบอะไรบ้าง?
  3. สถานการณ์ที่เหมาะสมที่จะใช้คืออะไร

ฉันพบคำถามที่เกี่ยวข้องที่นี่ใน SO แต่คำถามนั้นเกี่ยวกับ PHP และมันระบุว่าbใช้เพื่อระบุสตริงเป็นไบนารีซึ่งตรงข้ามกับ Unicode ซึ่งจำเป็นสำหรับรหัสที่จะเข้ากันได้กับ PHP เวอร์ชัน <6 เมื่อย้ายไปยัง PHP 6 ฉันไม่คิดว่านี่จะใช้กับ Python

ฉันพบเอกสารนี้ในเว็บไซต์ Python เกี่ยวกับการใช้uอักขระในไวยากรณ์เดียวกันเพื่อระบุสตริงเป็น Unicode น่าเสียดายที่มันไม่ได้พูดถึงตัวอักษรbทุกที่ในเอกสารนั้น

นอกจากนี้จากความอยากรู้มีสัญลักษณ์มากกว่าbและuนั่นเป็นสิ่งอื่นหรือไม่?

คำตอบ:


416

ในการอ้างอิงเอกสาร Python 2.x :

คำนำหน้า 'b' หรือ 'B' จะถูกละเว้นใน Python 2 มันบ่งบอกว่าตัวอักษรควรเป็นตัวอักษรไบต์ใน Python 3 (เช่นเมื่อรหัสถูกแปลงโดยอัตโนมัติด้วย 2to3) คำนำหน้า 'u' หรือ 'b' อาจตามด้วยคำนำหน้า 'r'

เอกสารหลาม 3ฯ :

ไบต์ตัวอักษรนำหน้าด้วย 'b' หรือ 'B' เสมอ พวกมันสร้างอินสแตนซ์ของชนิดไบต์แทนชนิด str อาจมีอักขระ ASCII ได้เท่านั้น ไบต์ที่มีค่าตัวเลขตั้งแต่ 128 ขึ้นไปจะต้องแสดงด้วย escapes


4
ดังนั้นดูเหมือนว่า Python <v3 จะไม่สนใจอักขระพิเศษนี้ จะเป็นกรณีใดใน v3 ที่คุณจะต้องใช้สตริง ab เมื่อเทียบกับสตริงปกติ?
Jesse Webb

5
@Gweebz - หากคุณพิมพ์สตริงในการเข้ารหัสแบบพิเศษแทนที่จะเป็นแบบ Unicode escapes (เช่น b '\ xff \ xfe \ xe12' แทนที่จะเป็น '\ u32e1')
Detly

7
อันที่จริงถ้าคุณนำเข้าunicode_literalsจาก__future__นี้สิ่งนี้จะ "ย้อนกลับ" พฤติกรรมของสตริงนี้ (ใน Python 2.x)
Romuald Brunet

34
การเล่าเรื่องภาษาธรรมดา ๆ อีกเล็กน้อยรอบ ๆ เอกสารที่ยกมาจะทำให้คำตอบนี้เป็นคำตอบที่ดีกว่า IMHO
Hack-R

2
มิฉะนั้นเป็นคำตอบสำหรับคนที่เข้าใจแล้ว
Rafael Eyng

679

Python 3.xทำให้เห็นความแตกต่างที่ชัดเจนระหว่างประเภท:

  • str= '...'literals = ลำดับของอักขระ Unicode (UTF-16 หรือ UTF-32 ขึ้นอยู่กับการรวบรวม Python)
  • bytes= b'...'literals = ลำดับของ octets (จำนวนเต็มตั้งแต่ 0 ถึง 255)

หากคุณคุ้นเคยกับ Java หรือ C #, คิดstrเป็นStringและเป็นbytes byte[]หากคุณคุ้นเคยกับ SQL คิดstrเป็นNVARCHARและbytesเป็นหรือBINARY BLOBหากคุณคุ้นเคยกับรีจิสทรีของ Windows คิดstrเป็นREG_SZและเป็นbytes REG_BINARYหากคุณคุ้นเคยกับ C (++) แล้วลืมทุกสิ่งที่คุณได้เรียนรู้charและเกี่ยวกับสตริงเพราะตัวละครไม่ใช่ไบต์BYTE ความคิดนั้นล้าสมัยมานาน

คุณใช้strเมื่อคุณต้องการแสดงข้อความ

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

คุณใช้bytesเมื่อคุณต้องการแสดงข้อมูลไบนารีระดับต่ำเช่น structs

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

คุณสามารถเข้ารหัส a strไปยังbytesวัตถุ

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

และคุณสามารถถอดรหัสเป็นbytesstr

>>> 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'...'literals = ลำดับของอักขระ Unicode = 3.xstr
  • str= '...'literals = sequences ของไบต์ / อักขระที่สับสน
    • โดยทั่วไปแล้วข้อความเข้ารหัสในการเข้ารหัสบางอย่างที่ไม่ระบุ
    • แต่ยังใช้เพื่อแสดงข้อมูลไบนารีเช่นstruct.packเอาต์พุต

เพื่อให้ง่ายต่อการเปลี่ยนแปลง 2.x-to-3.x b'...'ไวยากรณ์ตามตัวอักษรถูก backported เป็น Python 2.6 เพื่อให้สามารถแยกสตริงไบนารี่ (ซึ่งควรเป็นbytes3.x) จากสตริงข้อความ (ซึ่งควรเป็นstr3 .x) bคำนำหน้าไม่ทำอะไรเลยใน 2.x แต่บอก2to3สคริปต์ไม่ได้ที่จะแปลงเป็นสายอักขระ Unicode ใน 3.x.

ใช่แล้วb'...'ตัวอักษรใน Python มีจุดประสงค์เดียวกับที่ใช้ใน PHP

นอกจากนี้จากความอยากรู้มีสัญลักษณ์มากกว่า b และ u ที่ทำอย่างอื่นหรือไม่?

rคำนำหน้าสร้างสตริงดิบ (เช่นr'\t'เป็นเครื่องหมาย + tแทนแท็บ) และคำพูดที่สาม'''...'''หรือ"""..."""อนุญาตให้มีหลายคู่สายสายอักขระตัวอักษร


2
ขอบคุณ! ฉันเข้าใจหลังจากอ่านประโยคเหล่านี้: "เพื่อให้ง่ายต่อการเปลี่ยนแปลง 2.x-to-3.x, ไวยากรณ์ตัวอักษร b '... ' ถูก backported เป็น Python 2.6 เพื่อให้แยกสตริงไบนารี (ซึ่งควร เป็นไบต์ใน 3.x) จากสตริงข้อความ (ซึ่งควรเป็น str ใน 3.x) คำนำหน้า b ไม่ทำอะไรเลยใน 2.x แต่บอกสคริปต์ 2to3 ไม่ให้แปลงเป็นสตริง Unicode ใน 3.x "
tommy.carstensen

4
'A' == b'A' --> Falseตรวจสอบจริงๆทำให้มันชัดเจน ส่วนที่เหลือมันยอดเยี่ยม แต่จนถึงตอนนี้ฉันไม่เข้าใจว่าสตริงไบต์ไม่ได้
Wildcard

12
'שלום עולם' == 'hello world'
อีไล

12
นี่เป็นคำตอบที่ชัดเจนมากกว่าคำตอบที่ยอมรับซึ่งเป็นเพียงการอ้างอิงเอกสาร เอกสารสำหรับฉันไม่สมเหตุสมผลดังนั้นการให้บริบทเพิ่มเติมในเอกสารประกอบนั้นยอดเยี่ยม ขอบคุณ!
rayryeng

2
b "some string" .decode ('UTF-8') ฉันเชื่อว่านั่นคือสิ่งที่หลายคนกำลังมองหา
Marvin Thobejane

22

b หมายถึงสตริงไบต์

Bytes เป็นข้อมูลจริง เงื่อนไขเป็นสิ่งที่เป็นนามธรรม

หากคุณมีวัตถุสตริงหลายตัวอักษรและคุณใช้อักขระตัวเดียวมันจะเป็นสตริงและอาจมีขนาดมากกว่า 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
ไม่ได้อธิบายคำถามที่ Jesse Webb ถาม!
จันทราจันทรา

ฉันกำลังบอกว่าโดยไม่ต้องใช้วิธีการเข้ารหัสและถอดรหัสเอาต์พุตสตริงจะถูกขึ้นต้นด้วย b '' เป็นไพ ธ อนใช้เป็นชนิดไบต์แทนชนิดสตริงถ้าคุณไม่ต้องการรับผลลัพธ์เช่น b '... ใช้ข้างต้นนั่นคือสิ่งที่คุณไม่เข้าใจ?
Nani Chintha

จริงๆแล้วนี่คือคำตอบที่ตรงกับชื่อของคำถามที่ถาม: Q: "b'x 'ทำอะไร? A: "มัน 'x'.encode ()" นั่นคือสิ่งที่มันทำ คำถามที่เหลืออยากรู้มากกว่านี้ แต่ได้รับคำตอบแล้ว
Michael Erickson

10

นี่คือตัวอย่างที่กรณีที่ไม่มีที่bจะโยนTypeErrorข้อยกเว้นในหลาม 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ตัวอักษร (หรือเป็นstr2.x) และใช้ได้กับ 2.6+

rคำนำหน้าทำให้เกิดเครื่องหมายที่จะ "uninterpreted" (ไม่ได้ละเลยและความแตกต่างไม่ว่า)


สิ่งนี้ฟังดูผิดตามเอกสารที่ยกมาในคำตอบของ aix; b จะถูกละเว้นในเวอร์ชัน Python ที่ไม่ใช่ 3
Jesse Webb

2
มันจะเป็นแบบstr2.x ด้วยวิธีใดวิธีหนึ่งดังนั้นจึงอาจกล่าวได้ว่ามันถูกละเว้น ความแตกต่างสำคัญเมื่อคุณนำเข้าunicode_literalsจาก__future__โมดูล
Ignacio Vazquez-Abrams

6

นอกจากสิ่งที่คนอื่นพูดแล้วโปรดทราบว่าอักขระหนึ่งตัวในยูนิโค้ดอาจประกอบด้วยหลายไบต์สามารถประกอบด้วยหลายไบต์

วิธีที่ยูนิโค้ดทำงานคือใช้รูปแบบ ASCII แบบเก่า (รหัส 7 บิตที่ดูเหมือน 0xxx xxxx) และเพิ่มลำดับหลายไบต์ที่ทุกไบต์เริ่มต้นด้วย 1 (1xxx xxxx) เพื่อแสดงถึงอักขระที่เกิน ASCII ดังนั้น Unicode จะย้อนกลับ เข้ากันได้กับ 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'})

ในขวด / 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)

{ 'คีย์': 'คุ้มค่า'}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.