Một hàm chẳng cần đặt tên
Phần lớn hàm (function) trong Python được định nghĩa bằng def, có tên và nằm trong một tệp để có thể dùng lại. lambda là một lựa chọn nhỏ gọn hơn và không có tên, hữu ích trong vài trường hợp mà việc định nghĩa cả một hàm đầy đủ thì rườm rà hơn mức cần thiết.
Đây là hai dạng đặt cạnh nhau:
Hai hàm, làm đúng cùng một việc. Bản lambda nằm gọn trên một dòng vì đó chính là vai trò của nó: một hàm dùng xong là bỏ, cho một tình huống dùng xong là bỏ.
Cú pháp
lambda <params>: <expression>
<params>là danh sách tham số giống hệt danh sách màdefdùng, hỗ trợ giá trị mặc định,*argsvà**kwargs.<expression>là một biểu thức duy nhất, giá trị của nó trở thành giá trị trả về.
Ví dụ:
Không có từ khóa return. Giá trị của biểu thức được trả về một cách ngầm định.
Giới hạn duy nhất
Lambda chỉ chứa được một biểu thức. Bạn không thể đặt câu lệnh vào bên trong:
Nhưng bạn có thể dùng biểu thức ba ngôi:
Nếu cần nhiều hơn một biểu thức, đó là dấu hiệu để chuyển sang def.
Những chỗ lambda thực sự đáng dùng
Một lambda được gán cho biến gần như lúc nào cũng kém hơn một def có tên:
Cách này rõ ràng kém hơn def double(x): return x * 2: dễ đọc như nhau, nhưng bản lambda lại khiến trình gỡ lỗi hiện cái tên vô ích <lambda> trong stack trace.
Lambda chỉ thực sự tỏa sáng ở đúng một chỗ: làm đối số viết ngay tại chỗ cho các hàm bậc cao (higher-order function).
Key tùy chỉnh khi sắp xếp
Trường hợp kinh điển:
Đối số key của sorted cần một hàm nhận vào một phần tử và trả về giá trị dùng để sắp xếp. Một lambda một dòng là vừa khít, còn viết cả một def đầy đủ thì quá nặng nề cho việc nhỏ như vậy.
Bạn có thể sắp xếp theo nhiều trường bằng một tuple:
min, max, filter, map
Câu chuyện tương tự: tất cả đều nhận một đối số hàm tùy chọn:
Với map và filter, list comprehension thường còn rõ ràng hơn:
Vì lý do này, phần lớn lập trình viên Python chọn comprehension thay vì map/filter. lambda vẫn rất hợp với sorted, min và max, vì ở đó không có cách viết tắt nào bằng comprehension.
Lambda và operator
Khi lambda của bạn chỉ làm việc "lấy một khóa" hay "lấy một thuộc tính", module operator của Python có những lựa chọn nhanh hơn và rõ ràng hơn:
Lợi ích không lớn, nhưng trong code vốn đã import operator, cách này đọc mang tính khai báo hơn một chút.
Khi nào quay lại dùng def
Nếu có bất kỳ điều nào dưới đây đúng, hãy viết def:
- Logic không gói gọn được trong một biểu thức.
- Bạn muốn đặt tên cho hàm vì cái tên giúp code dễ đọc hơn.
- Bạn sẽ dùng cùng logic đó ở nhiều chỗ.
- Hàm cần một docstring (lambda không có docstring được).
Nhớ rằng: Python không chấm điểm theo số dòng. Một hàm có tên dài ba dòng gần như luôn dễ đọc hơn một lambda một dòng khi logic không còn đơn giản.
Tiếp theo: decorator
Lambda đưa hàm đi khắp nơi như một giá trị. Decorator đẩy ý tưởng đó đi xa thêm một bước: chúng cho phép bạn bọc bất kỳ hàm nào bằng hành vi dùng lại được, như ghi log, đo thời gian, cache hay xác thực, chỉ với một dấu @ ở dòng phía trên. Đó là nội dung của trang tiếp theo.
Câu hỏi thường gặp
Lambda trong Python là gì?
lambda là một hàm ngắn, không có tên, viết gọn trên một dòng. lambda x: x * 2 tương đương def double(x): return x * 2, chỉ khác là không có tên. Lambda hữu ích nhất khi bạn cần một hàm nhỏ để truyền làm đối số cho một hàm khác.
Khi nào nên dùng lambda thay vì def?
Dùng lambda cho những hàm dùng một lần, chỉ gồm một biểu thức và được truyền thẳng vào những hàm như sorted, max hay filter. Với mọi thứ có thân dài hơn một biểu thức, hoặc mọi thứ bạn muốn đặt tên, hãy dùng def. Hàm có tên gần như lúc nào cũng dễ hiểu hơn.
Lambda có những giới hạn gì?
Lambda chỉ chứa được một biểu thức, không chứa câu lệnh. Không gán giá trị, không có khối if (dù bạn vẫn dùng được biểu thức ba ngôi a if cond else b), không có logic nhiều dòng. Nếu thấy mình đang vật lộn với những giới hạn này, hãy chuyển sang def.