3.1 Giới thiệu về closures
Closure là một hàm bắt giữ các biến từ phạm vi bao quanh nó, ngay cả sau khi phạm vi đó đã hoàn tất thực thi. Điều này có nghĩa là closure có thể "nhớ" các giá trị biến từ phạm vi bên ngoài của nó và tiếp tục làm việc với chúng, ngay cả khi phạm vi đó không còn hoạt động nữa.
Để hiểu cách hoạt động của closures, hãy xem ví dụ sau:
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
closure = outer_function(10)
print(closure(5)) # Kết quả: 15
Hãy cùng nhau phân tích đoạn mã trên:
Hàm bên ngoài (outer_function)
: Hàm này nhận
đối số x
và định nghĩa một hàm bên trong inner_function
,
nhận đối số y
và trả về tổng của x
và y
. Hàm
inner_function
không được gọi bên trong
outer_function
, chỉ được khai báo thôi.
Hàm bên trong (inner_function)
: Hàm này
được trả về từ outer_function
và giữ một tham chiếu tới
giá trị của x
, đã được truyền vào outer_function
.
Closure: Biến closure
trở thành
closure, "nhớ" giá trị x
(trong trường hợp này là 10) và
có thể sử dụng nó khi được gọi.
Thường thì không ai có thể dùng closures một cách thuần thục ngay lần đầu. Vì vậy, hãy cùng thử nâng cao sự hiểu biết của bạn về các closures qua các ví dụ nhé.
3.2 Ví dụ về việc sử dụng closures
Tạo hàm generator
Closures có thể được sử dụng để tạo các hàm generator, tạo ra các dãy giá trị.
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
counter = make_counter()
print(counter()) # Kết quả: 1
print(counter()) # Kết quả: 2
print(counter()) # Kết quả: 3
Giải thích:
Hàm generator (make_counter)
: Hàm này tạo
một biến count
và trả về một hàm bên trong counter
,
hàm này tăng giá trị của count
và trả về nó.
Closure: Hàm counter
lưu trữ trạng thái
của biến count
và có thể thay đổi nó mỗi khi được gọi.
Tạo hàm với cấu hình
Closures có thể được sử dụng để tạo ra các hàm với cấu hình được xác định từ trước.
def make_multiplier(factor):
def multiplier(x):
return x * factor
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # Kết quả: 10
print(triple(5)) # Kết quả: 15
Giải thích:
Hàm cấu hình (make_multiplier)
: Hàm này
nhận một hệ số factor
và trả về một hàm nội bộ multiplier
,
hàm này nhân giá trị đầu vào với factor
.
Closures: Các hàm double
và triple
là closures,
chúng lưu trữ các giá trị factor
riêng của mình và sử dụng chúng để
nhân.
Lọc dữ liệu với tham số
Closures có thể rất hữu ích để tạo ra các hàm lọc với tham số.
def make_filter(threshold):
def filter_func(value):
return value > threshold
return filter_func
filter_above_10 = make_filter(10)
data = [5, 10, 15, 20]
filtered_data = list(filter(filter_above_10, data))
print(filtered_data) # Kết quả: [15, 20]
Giải thích:
Hàm lọc (make_filter)
: Hàm này nhận
một giá trị ngưỡng threshold
và trả về một hàm nội bộ filter_func
,
hàm này kiểm tra xem giá trị có lớn hơn ngưỡng không.
Closure: Hàm filter_func
lưu trữ giá trị threshold
và sử dụng nó để lọc dữ liệu.
3.3 Ưu và nhược điểm của closures
Ưu điểm của việc dùng closures
Đóng gói trạng thái: Closures cho phép đóng gói trạng thái trong hàm, tránh việc dùng biến toàn cục và cải thiện tính dễ đọc và khả năng bảo trì của mã.
Linh hoạt: Closures có thể được sử dụng để tạo ra các hàm với cấu hình hoặc hành vi nhất định, làm cho mã linh hoạt và thích ứng hơn.
Lập trình hàm: Closures là một khái niệm quan trọng trong lập trình hàm, cho phép tạo ra các hàm bậc cao và các cấu trúc hàm khác.
Hạn chế và vấn đề tiềm ẩn
Mặc dù có nhiều ưu điểm, closures cũng có những hạn chế riêng:
Sử dụng bộ nhớ: Closures có thể giữ các tham chiếu tới các đối tượng không còn được sử dụng, điều này có thể dẫn đến rò rỉ bộ nhớ.
Độ khó trong debug: Closures có thể làm phức tạp việc debug mã, vì trạng thái của các biến có thể không rõ ràng.
GO TO FULL VERSION