Khái niệm về Serialization và Deserialization
Trong quá trình phát triển phần mềm, việc lưu trữ trạng thái của đối tượng hoặc truyền tải dữ liệu giữa các thành phần hệ thống là yêu cầu bắt buộc. Quá trình này bao gồm hai thao tác chính:
- Serialization (Tuần tự hóa): Là quá trình chuyển đổi một đối tượng trong bộ nhớ (như list, dict, class instance) sang một định dạng có thể lưu trữ được (như byte stream hoặc chuỗi văn bản) để ghi vào file hoặc truyền qua mạng.
- Deserialization (Giải tuần tự hóa): Là quá trình ngược lại, chuyển đổi dữ liệu từ file hoặc luồng dữ liệu nhận được trở lại thành đối tượng trong bộ nhớ để chương trình có thể xử lý.
Python cung cấp hai module phổ biến nhất để thực hiện việc này là json và pickle.
1. Sử dụng module JSON cho dữ liệu có cấu trúc
JSON (JavaScript Object Notation) là định dạng trao đổi dữ liệu nhẹ, dễ đọc với con người và tương thích với hầu hết các ngôn ngữ lập trình hiện nay. Trong Python, module json giúp xử lý các kiểu dữ liệu cơ bản như dictionary và list.
Ghi và đọc file JSON
Để lưu trữ dữ liệu vào file, chúng ta sử dụng hàm json.dump(). Để đọc ngược lại, chúng ta dùng json.load().
import json
# Dữ liệu mẫu
server_info = {
"hostname": "prod-server-01",
"ip_address": "192.168.1.50",
"services": ["nginx", "postgresql", "redis"],
"is_active": True
}
# Ghi dữ liệu vào file
storage_file = "config.json"
with open(storage_file, "w", encoding="utf-8") as f:
json.dump(server_info, f, indent=4)
# Đọc dữ liệu từ file
with open(storage_file, "r", encoding="utf-8") as f:
loaded_data = json.load(f)
print(f"Dữ liệu đã tải: {loaded_data}")
print(f"Kiểu dữ liệu: {type(loaded_data)}")
Xử lý chuỗi JSON
Nếu bạn chỉ cần chuyển đổi đối tượng thành chuỗi (string) thay vì ghi file, hãy sử dụng dumps và loads.
import json
user_settings = {"theme": "dark", "font_size": 14, "notifications": False}
# Chuyển dict thành string (Serialization)
json_string = json.dumps(user_settings)
print(f"JSON String: {json_string}")
# Chuyển string ngược lại thành dict (Deserialization)
data_dict = json.loads(json_string)
print(f"Khôi phục dict: {data_dict['theme']}")
2. Sử dụng module Pickle cho dữ liệu đặc thù của Python
Khác với JSON, pickle là một định dạng nhị phân chỉ dành riêng cho Python. Ưu điểm của nó là có thể tuần tự hóa hầu hết các đối tượng phức tạp của Python (bao gồm cả các class tự định nghĩa), nhưng nhược điểm là không thể đọc được bởi các ngôn ngữ khác và tiềm ẩn rủi ro bảo mật nếu load dữ liệu từ nguồn không tin cậy.
import pickle
def calculate_tax(amount):
return amount * 0.1
# Lưu trữ một hàm hoặc đối tượng phức tạp
data_to_store = {
"id": 1001,
"logic": calculate_tax,
"metadata": (1, 2, 3)
}
# Tuần tự hóa ra byte
binary_data = pickle.dumps(data_to_store)
print(f"Dữ liệu nhị phân: {binary_data[:20]}...")
# Giải tuần tự hóa
restored_data = pickle.loads(binary_data)
result = restored_data["logic"](500)
print(f"Kết quả thực thi hàm sau khi khôi phục: {result}")
Lưu trữ Pickle vào file nhị phân
import pickle
app_state = {"session_id": "XYZ123", "retry_count": 5}
# Ghi file nhị phân (chú ý mode 'wb')
with open("state.pkl", "wb") as f:
pickle.dump(app_state, f)
# Đọc file nhị phân (chú ý mode 'rb')
with open("state.pkl", "rb") as f:
recovered_state = pickle.load(f)
print(recovered_state)
3. Tuần tự hóa các đối tượng Class tùy chỉnh với JSON
Mặc định, JSON không biết cách xử lý các instance của Class tự định nghĩa. Chúng ta cần cung cấp một hàm chuyển đổi thông qua tham số default và object_hook.
import json
class Smartphone:
def __init__(self, brand, model):
self.brand = brand
self.model = model
def __repr__(self):
return f"Smartphone({self.brand}, {self.model})"
def serialize_device(obj):
if isinstance(obj, Smartphone):
return {"__type__": "Smartphone", "brand": obj.brand, "model": obj.model}
raise TypeError("Object not serializable")
def deserialize_device(d):
if "__type__" in d and d["__type__"] == "Smartphone":
return Smartphone(d["brand"], d["model"])
return d
# Khởi tạo đối tượng
my_phone = Smartphone("Apple", "iPhone 15")
# Chuyển đổi sang JSON
json_output = json.dumps(my_phone, default=serialize_device)
print(f"Serialized JSON: {json_output}")
# Khôi phục từ JSON
new_phone_obj = json.loads(json_output, object_hook=deserialize_device)
print(f"Restored Object: {new_phone_obj}")