bytes ใน Python คือลำดับของจำนวนเต็มขนาด 8 บิต (0-255) ที่ไม่เปลี่ยนแปลง (immutable sequence of integers) ซึ่งแตกต่างจาก String ตรงที่ String คือลำดับของ Unicode characters (ตัวอักษร) ส่วน bytes คือข้อมูลดิบที่คอมพิวเตอร์เข้าใจ และนี่คือเหตุผลว่าทำไมไลบรารีหลายตัว เช่น bcrypt จึงต้องการข้อมูลในรูปแบบ bytes
ทำไมต้องใช้ bytes?
- การสื่อสารกับระบบภายนอก: เมื่อคุณอ่าน/เขียนไฟล์ภาพ, ไฟล์เสียง, ไฟล์วิดีโอ, หรือสื่อสารผ่านเครือข่าย (Socket programming) ข้อมูลเหล่านี้มักจะอยู่ในรูปแบบไบนารี (bytes) ไม่ใช่ข้อความ
- ความเข้ากันได้ของไลบรารี: ไลบรารีที่จัดการกับข้อมูลระดับต่ำ (Low-level data) หรือเกี่ยวข้องกับ cryptographic operations (เช่น Hashing, Encryption) มักจะออกแบบมาให้รับข้อมูลเป็น bytes เพื่อหลีกเลี่ยงปัญหาเรื่อง Encoding และรักษาความสมบูรณ์ของข้อมูลไบนารี
- ประสิทธิภาพ: การทำงานกับ bytes โดยตรงบางครั้งก็มีประสิทธิภาพมากกว่าเมื่อคุณไม่จำเป็นต้องแปลงเป็น String และ Encoding/Decoding บ่อยๆ
มีหลายวิธีในการสร้างและจัดการกับ bytes ใน Python
1. การสร้าง bytes Literal
คุณสามารถสร้าง bytes ได้โดยการนำหน้า String ด้วย b หรือ B:
โค้ด: เลือกทั้งหมด
# สร้าง bytes literal
my_bytes = b"Hello, world!"
print(my_bytes) # Output: b'Hello, world!'
print(type(my_bytes)) # Output: <class 'bytes'>
# แต่ละองค์ประกอบคือ integer (ASCII/UTF-8 value)
print(my_bytes[0]) # Output: 72 (ASCII value for 'H')
print(my_bytes[1]) # Output: 101 (ASCII value for 'e')
2. การแปลง String เป็น bytes ด้วย .encode()
นี่คือวิธีที่พบบ่อยที่สุดและสำคัญมากเมื่อคุณต้องการส่ง String ไปยังฟังก์ชันที่ต้องการ bytes
โค้ด: เลือกทั้งหมด
my_string = "สวัสดีครับ" # เป็น String (Unicode)
# แปลง String เป็น bytes โดยใช้ encoding ที่ระบุ
# UTF-8 เป็น encoding ที่นิยมใช้และดีที่สุดสำหรับภาษาไทยและภาษาอื่นๆ
encoded_bytes_utf8 = my_string.encode('utf-8')
print(encoded_bytes_utf8)
print(type(encoded_bytes_utf8))
ผลลัพธ์
โค้ด: เลือกทั้งหมด
b'\xe0\xb8\xaa\xe0\xb8\xa7\xe0\xb8\xb1\xe0\xb8\xaa\xe0\xb8\x94\xe0\xb8\xb5\xe0\xb8\x84\xe0\xb8\xa3\xe0\xb8\xb1\xe0\xb8\x9a'
<class 'bytes'>
3. การแปลง bytes กลับเป็น String ด้วย .decode()
เมื่อคุณได้รับข้อมูลเป็น bytes และต้องการนำมาแสดงผลเป็นข้อความที่มนุษย์อ่านได้ คุณจะต้อง .decode() มันกลับเป็น String
โค้ด: เลือกทั้งหมด
# สมมติว่าได้ bytes มาจากที่ไหนสักแห่ง (เช่น จากการอ่านไฟล์หรือเครือข่าย)
some_bytes = b'\xe0\xb8\xaa\xe0\xb8\xa7\xe0\xb8\xb1\xe0\xb8\xaa\xe0\xb8\x94\xe0\xb8\xb5\xe0\xb8\x84\xe0\xb8\xa3\xe0\xb8\xb1\xe0\xb8\x9a'
# แปลง bytes กลับเป็น String โดยใช้ encoding ที่ถูกต้อง
# หากใช้ encoding ผิด อาจได้ผลลัพธ์ที่ไม่ถูกต้องหรือเกิด UnicodeDecodeError
decoded_string = some_bytes.decode('utf-8')
print(decoded_string)
print(type(decoded_string))
ผลลัพธ์ ---
ตัวอย่างการใช้งาน bytes()
เราจะยกตัวอย่างการ hash password ด้วย bcrypt เราจะเห็นว่า bcrypt ต้องการข้อมูลรหัสผ่านในรูปแบบ bytes นี่คือเหตุผลที่เราใช้ password.encode('utf-8')
โค้ด: เลือกทั้งหมด
import bcrypt
def hash_password(password_str):
# 1. แปลง String ของรหัสผ่านให้เป็น bytes
# bcrypt.hashpw ต้องการ bytes เป็น input
password_bytes = password_str.encode('utf-8')
# 2. สร้าง salt และ hash รหัสผ่าน
hashed_password_bytes = bcrypt.hashpw(password_bytes, bcrypt.gensalt())
return hashed_password_bytes
def verify_password(plain_password_str, hashed_password_bytes):
# 1. แปลง String ของรหัสผ่านที่ผู้ใช้ป้อนให้เป็น bytes
# bcrypt.checkpw ก็ต้องการ bytes เป็น input
plain_password_bytes = plain_password_str.encode('utf-8')
# 2. ตรวจสอบรหัสผ่าน
return bcrypt.checkpw(plain_password_bytes, hashed_password_bytes)
# --- การใช้งานจริง ---
plain_pwd = "MySecretPassword123"
# Hash
hashed_pwd_bytes = hash_password(plain_pwd)
print(f"Hashed (bytes): {hashed_pwd_bytes}")
print(f"Hashed (string for display): {hashed_pwd_bytes.decode('utf-8')}")
# Verify
is_correct = verify_password("MySecretPassword123", hashed_pwd_bytes)
print(f"Password verified: {is_correct}")
- password_str.encode('utf-8'): เราใช้ .encode('utf-8') เพื่อแปลงรหัสผ่านจาก str (String) ที่ผู้ใช้ป้อนเข้ามา ให้เป็น bytes ก่อนที่จะส่งให้ฟังก์ชัน bcrypt.hashpw()
- hashed_pwd_bytes.decode('utf-8'): เมื่อ bcrypt.hashpw() คืนค่า Hash ออกมา จะอยู่ในรูปแบบ bytes หากเราต้องการนำไปแสดงผลหรือเก็บในฐานข้อมูลที่รองรับ String (เช่น MySQL VARCHAR), เราอาจต้อง .decode('utf-8') ให้กลับเป็น str ก่อน อย่างไรก็ตาม บางฐานข้อมูลก็สามารถเก็บ bytes ได้โดยตรง และการเก็บเป็น bytes โดยไม่แปลงเป็น str ก่อนจะมีความบริสุทธิ์ของข้อมูลมากกว่า
- plain_password_str.encode('utf-8') ในฟังก์ชัน verify_password(): เช่นเดียวกัน รหัสผ่านที่ผู้ใช้ป้อนเข้ามาเพื่อ Login ก็ยังคงต้องถูกแปลงเป็น bytes ก่อนส่งให้ bcrypt.checkpw()
สรุป
bytes ใน Python คือแนวคิดพื้นฐานที่สำคัญเมื่อคุณต้องจัดการกับข้อมูลไบนารีโดยตรง ซึ่งเป็นเรื่องปกติในการเขียนโปรแกรมจริง ไม่ว่าจะเป็นการปกป้องรหัสผ่านด้วย Bcrypt, การอ่าน/เขียนไฟล์ที่ไม่ใช่ข้อความ, หรือการสื่อสารผ่านเครือข่าย
การจดจำความแตกต่างระหว่าง String (text data) กับ Bytes (binary data) และการรู้วิธีใช้ .encode() และ .decode() อย่างถูกต้อง จะช่วยให้คุณหลีกเลี่ยงข้อผิดพลาดทั่วไปและเขียนโค้ด Python ที่แข็งแกร่งและปลอดภัยยิ่งขึ้นได้อย่างแน่นอนครับ
อ้างอิง
- https://www.mindphp.com/คู่มือ/73-คืออะ ... ออะไร.html
- https://www.mindphp.com/คู่มือ/73-คืออะ ... -unit.html
- https://www.mindphp.com/developer/tips- ... ython.html
- https://www.mindphp.com/developer/tips- ... ython.html
- https://www.mindphp.com/developer/tips- ... ython.html