Nâng Cao Về Generator Và Các Dạng Comprehension Trong Python

Phương thức send() trong Generator

Phương thức send() có chức năng tương tự như next() là kích hoạt generator và lấy giá trị tiếp theo. Tuy nhiên, điểm khác biệt lớn nhất là send() cho phép truyền một giá trị vào bên trong generator tại vị trí yield đang tạm dừng.

Một số lưu ý quan trọng:

  • Lần đầu tiên kích hoạt generator, bạn bắt buộc phải dùng next() hoặc send(None) để generator chạy đến điểm yield đầu tiên.
  • Lệnh yield cuối cùng trong hàm không thể nhận giá trị truyền từ bên ngoài vào vì generator sẽ kết thúc ngay sau đó.
def state_machine():
    print("Khởi tạo hệ thống...")
    status = yield "READY"
    print(f"Nhận lệnh điều khiển: {status}")
    
    print("Đang xử lý tác vụ...")
    next_status = yield "PROCESSING"
    print(f"Cập nhật trạng thái mới: {next_status}")
    
    yield "COMPLETED"

gen = state_machine()
print(next(gen))          # Khởi động generator
print(gen.send("START"))  # Truyền dữ liệu vào yield đầu tiên
print(gen.send("STOP"))   # Truyền dữ liệu vào yield thứ hai

Ứng dụng Generator để tính toán trạng thái liên tục

Generator rất hữu ích để duy trì trạng thái và tính toán các giá trị tích lũy, chẳng hạn như tính nhiệt độ trung bình từ các cảm biến liên tục gửi dữ liệu.

def temperature_monitor():
    total_temp = 0.0
    readings = 0
    avg_temp = 0.0
    
    while True:
        new_temp = yield avg_temp, readings
        total_temp += new_temp
        readings += 1
        avg_temp = total_temp / readings

monitor = temperature_monitor()
next(monitor)  # Bắt buộc phải gọi next() lần đầu để khởi tạo

print(monitor.send(22.5))  # Trả về (22.5, 1)
print(monitor.send(23.0))  # Trả về (22.75, 2)
print(monitor.send(21.5))  # Trả về (22.333..., 3)

List Comprehension và Generator Expression

List comprehension tạo ra một danh sách đầy đủ trong bộ nhớ, trong khi generator expression trả về một đối tượng generator, giúp tiết kiệm bộ nhớ đáng kể khi làm việc với tập dữ liệu lớn.

# List Comprehension - Chiếm dụng bộ nhớ vì lưu toàn bộ phần tử
items_list = [f"Product_{i}" for i in range(5)]
print(items_list)

# Generator Expression - Hầu như không chiếm bộ nhớ, sinh ra giá trị khi được gọi
items_gen = (f"Node_{i**2}" for i in range(5))
for item in items_gen:
    print(item)

Các biến thể nâng cao của List Comprehension

Chúng ta có thể kết hợp các điều kiện lọc và xử lý danh sách lồng nhau một cách gọn gàng.

# Lọc các số chia hết cho 4 trong khoảng từ 0 đến 40
divisible_by_4 = [n for n in range(41) if n % 4 == 0]
print(divisible_by_4)

# Tính bình phương của các số chia hết cho 4
squared_div_4 = [n**2 for n in range(41) if n % 4 == 0]
print(squared_div_4)

# Trích xuất tên từ danh sách lồng nhau có chứa từ khóa 'Admin'
users = [
    ['Guest', 'Admin_01', 'UserA'], 
    ['Admin_02', 'Manager', 'SuperAdmin']
]
admin_users = [name for group in users for name in group if 'Admin' in name]
print(admin_users)

Dictionary Comprehension

Tương tự như list, dictionary comprehension cho phép tạo và biến đổi từ điển một cách nhanh chóng.

# Đảo ngược key và value của từ điển
original_dict = {'x': 100, 'y': 200}
reversed_dict = {val: key for key, val in original_dict.items()}
print(reversed_dict)

# Chuẩn hóa key về chữ thường và gộp giá trị của các key giống nhau (không phân biệt hoa thường)
raw_scores = {'math': 8, 'MATH': 2, 'physics': 9, 'PHYSICS': 1}

# Cách an toàn và tối ưu để gộp các key trùng lặp
unique_keys = {k.lower() for k in raw_scores.keys()}
merged_scores = {
    k: sum(v for orig_k, v in raw_scores.items() if orig_k.lower() == k) 
    for k in unique_keys
}
print(merged_scores)

Set Comprehension

Set comprehension tự động loại bỏ các phần tử trùng lặp trong quá trình tạo tập hợp.

# Tính bình phương và tự động loại bỏ giá trị trùng lặp
unique_squares = {abs(x)**2 for x in [-3, 3, -4, 4, 5]}
print(unique_squares)

Bài tập thực hành với Comprehension

# 1. Lọc các chuỗi có độ dài lớn hơn 4 và chuyển thành chữ thường
words = ['apple', 'banana', 'kiwi', 'strawberry', 'fig']
filtered_words = [w.lower() for w in words if len(w) > 4]
print(filtered_words)

# 2. Tạo danh sách các tuple (a, b) với a là số chẵn từ 2-10, b là số lẻ từ 1-10
pairs = [(a, b) for a in range(2, 11, 2) for b in range(1, 11, 2)]
print(pairs)

# 3. Trích xuất cột thứ 2 từ một ma trận 2 chiều
matrix = [
    [10, 20, 30],
    [40, 50, 60],
    [70, 80, 90]
]
second_column = [row[1] for row in matrix]
print(second_column)

Xử lý File với Generator

Generator là công cụ lý tưởng để xử lý các file log có kích thước lớn mà không làm tràn bộ nhớ.

# Đọc file log và chỉ in ra các dòng chứa từ khóa 'ERROR'
def filter_log_file(filepath='system.log'):
    with open(filepath, 'r', encoding='utf-8') as file:
        for line in file:
            if 'ERROR' in line:
                print(line.strip())

# Generator đọc file log, thêm tiền tố '[ALERT]' vào trước mỗi dòng chứa 'ERROR'
def alert_log_generator(filepath='system.log'):
    with open(filepath, 'r', encoding='utf-8') as file:
        for line in file:
            if 'ERROR' in line:
                yield f"[ALERT] {line.strip()}"

# Sử dụng generator để xử lý từng dòng
log_gen = alert_log_generator()
for alert in log_gen:
    print(alert)

Thẻ: python generator list-comprehension dictionary-comprehension set-comprehension

Đăng vào ngày 14 tháng 9 lúc 06:39