Hàm Lambda của Python: Cú pháp, cách sử dụng thực tế và khi nào không nên sử dụng chúng

  1. Trang chủ
  2. Blog
  3. Phát triển phần mềm

Phát triển phần mềm

Hàm Lambda của Python: Cú pháp, cách sử dụng thực sự và khi nào không nên sử dụng chúng

Lambda là một hàm nhỏ mà bạn có thể viết thành một dòng, ngay tại nơi bạn cần. Tìm hiểu cú pháp, những nơi mà lambda thực sự trợ giúp, cái bẫy thu hút các nhà phát triển có kinh nghiệm và khi nào thì một chức năng bình thường sẽ tốt hơn.

Đọc 8 phút
Hàm lambda của Python: cú pháp, cách sử dụng thực tế và khi nào không nên sử dụng chúng

Điểm chính

  • lambda là một hàm ẩn danh được giới hạn ở một biểu thức duy nhất.
  • Cách sử dụng tốt nhất của nó là làm đối số ngắn, đặc biệt là key cho sorted, min và max.
  • Việc hiểu danh sách thường rõ ràng hơn map hoặc filter với lambda.
  • Nếu bạn gán lambda cho một tên, thay vào đó hãy viết def.

Bạn cần sắp xếp sản phẩm theo giá. Viết một hàm được đặt tên riêng chỉ để nói “sử dụng giá” có cảm giác như rất nhiều nghi lễ. Hàm lambda Python cho phép bạn xác định đoạn logic nội tuyến nhỏ đó, chính xác ở nơi bạn sử dụng.

Lambda rất tiện dụng nhưng chúng cũng dễ bị lạm dụng. Hướng dẫn này cho thấy chúng thực sự hữu ích ở đâu và làm cho mã khó đọc hơn ở đâu. Chúng tôi đã chạy mọi ví dụ trên Python 3.13 và kết quả hiển thị là từ lần chạy đó.

Lambda là gì?

Lambda là một hàm không có tên, được viết bằng từ khóa lambda:

lambda arguments: expression

Nó nhận bất kỳ số lượng đối số nào và tự động trả về giá trị của một biểu thức. Không có từ khóa return và không có nội dung câu lệnh.

square = lambda x: x * x
print(square(4))                     # 16

print((lambda a, b=10: a + b)(5))    # 15

Dòng thứ hai xác định lambda với đối số mặc định và gọi nó ngay lập tức. Bạn hiếm khi viết mã này bằng mã thực, nhưng nó cho thấy lambda là một đối tượng hàm thông thường.

lambda vs def

Hai hàm này tạo ra các hàm hoạt động giống nhau:

square = lambda x: x * x

def square_def(x):
    return x * x

print(square(4), square_def(4))                 # 16 16
print(square.__name__, square_def.__name__)     # <lambda> square_def

Nhìn vào những cái tên. Mọi lambda chỉ được gọi là <lambda>, vì vậy các thông báo lỗi và nhật ký không thể cho bạn biết cái nào bị lỗi. Đây là lý do chính khiến các hướng dẫn về kiểu như PEP 8 khuyên dùng def bất cứ khi nào bạn muốn đặt tên cho hàm.

tính năng lambda chắc chắn
Tên Ẩn danh Được đặt tên
Thân hình Một biểu thức Bất kỳ số lượng báo cáo
Trở lại ngầm Rõ ràng return
Gợi ý về chuỗi tài liệu và loại Không được hỗ trợ Được hỗ trợ
Truy nguyên có thể đọc được Chương trình <lambda> Hiển thị tên
Tốt nhất cho Những lập luận ngắn gọn Mọi thứ khác

Sắp xếp bằng khóa: cách sử dụng tốt nhất

Các hàm như sorted, min và max chấp nhận hàm key quyết định nội dung cần so sánh. Đây là nơi lambdas tỏa sáng:

products = [("pen", 10), ("bag", 900), ("book", 250)]

sorted(products, key=lambda p: p[1])
# [('pen', 10), ('book', 250), ('bag', 900)]

max(products, key=lambda p: p[1])
# ('bag', 900)

Để sắp xếp theo nhiều thứ, hãy trả về một bộ dữ liệu. Ở đây, mọi người được sắp xếp theo độ tuổi, già nhất trước tiên và sau đó theo tên:

people = [{"name": "Asha", "age": 31}, {"name": "Ben", "age": 25},
          {"name": "Dev", "age": 31}]

[p["name"] for p in sorted(people, key=lambda p: (-p["age"], p["name"]))]
# ['Asha', 'Dev', 'Ben']

Dấu trừ chỉ đảo ngược thứ tự của số. Đôi khi bạn hoàn toàn không cần lambda vì một hàm hiện có đã thực hiện công việc đó. So sánh cách sắp xếp mặc định với cách sắp xếp không phân biệt chữ hoa chữ thường:

names = ["Asha", "ben", "Chitra", "dev"]

sorted(names)                  # ['Asha', 'Chitra', 'ben', 'dev']
sorted(names, key=str.lower)   # ['Asha', 'ben', 'Chitra', 'dev']

Mặc định đặt tất cả các từ viết hoa đầu tiên. Vượt qua str.lower sẽ sửa lỗi đó mà không có bất kỳ lambda nào. Mô-đun operator cung cấp các trợ giúp tương tự, chẳng hạn như itemgetter(1) cho lambda p: p[1].

bản đồ và bộ lọc

map áp dụng một hàm cho mọi mục và filter giữ các mục mà nó trả về đúng. Cả hai đều hoạt động với lambdas, nhưng so sánh từng cái với cách hiểu danh sách:

nums = [1, 2, 3, 4, 5, 6]

list(map(lambda n: n * 10, nums))      # [10, 20, 30, 40, 50, 60]
[n * 10 for n in nums]                 # [10, 20, 30, 40, 50, 60]

list(filter(lambda n: n % 2 == 0, nums))   # [2, 4, 6]
[n for n in nums if n % 2 == 0]            # [2, 4, 6]

Các kết quả giống hệt nhau và hầu hết các nhà phát triển Python đều thấy phần hiểu dễ đọc hơn. Cũng lưu ý rằng map và filter trả về các trình vòng lặp lười biếng, vì vậy bạn cần list() để xem các giá trị. Hướng dẫn của chúng tôi về hiểu danh sách Python trình bày chi tiết về phong cách đó. map vẫn đọc tốt với hàm được đặt tên hiện có, như trong map(str.strip, lines).

giảm bớt

functools.reduce kết hợp các mục thành một giá trị duy nhất, mang lại kết quả đang chạy:

from functools import reduce

reduce(lambda acc, n: acc + n, nums, 0)   # 21
sum(nums)                                 # 21

Đối với các công việc thông thường, chẳng hạn như tính tổng, hãy sử dụng các công cụ có sẵn như sum, max hoặc any. Giữ reduce cho các trường hợp hiếm hơn và xem xét vòng lặp đơn giản nếu lambda bắt đầu trông phức tạp.

Điều kiện trong lambda

Bạn không thể sử dụng câu lệnh if trong lambda, nhưng bạn có thể sử dụng biểu thức điều kiện:

label = lambda total: "large" if total >= 1000 else "small"

label(1200), label(300)
# ('large', 'small')

Một điều kiện là được. Một khi bạn bắt đầu lồng chúng, người đọc phải làm việc chăm chỉ, đó là một dấu hiệu rõ ràng để chuyển sang def với các câu lệnh if thông thường.

Lambda trả về các hàm

Một hàm có thể tạo và trả về một lambda ghi nhớ một giá trị từ môi trường xung quanh nó:

def multiplier(n):
    return lambda x: x * n

double = multiplier(2)
double(7)   # 14

Điều này hoạt động nhờ các bao đóng mà bài viết của chúng tôi về các bao đóng JavaScript giải thích bằng một ngôn ngữ khác. functools.partial của Python cung cấp một cách khác để điền trước các đối số.

Cái bẫy ràng buộc muộn

Điều này cuối cùng đã bắt được gần như tất cả mọi người. Chúng tôi đã tạo ba lambda trong một vòng lặp, hy vọng mỗi cái sẽ trả về số riêng của nó:

funcs = [lambda: i for i in range(3)]
[f() for f in funcs]

# [2, 2, 2]

Cả ba đều trả về 2. Một lambda không nắm bắt đượcgiá trịcủaikhi nó được tạo ra. Nó tra cứu biến khi nóđược gọi là, và lúc đó vòng lặp đã kết thúc, để lạiiở mức 2. Cách khắc phục thông thường là lấy giá trị làm đối số mặc định, vì các giá trị mặc định được đánh giá tại thời điểm xác định:

funcs = [lambda i=i: i for i in range(3)]
[f() for f in funcs]

# [0, 1, 2]

Điều này không phải là duy nhất đối với lambdas, vì def bên trong vòng lặp cũng hoạt động theo cách tương tự. Nó chỉ xuất hiện thường xuyên hơn với lambdas, vì chúng thường được tạo trong các vòng lặp, chẳng hạn như khi đính kèm các lệnh gọi lại nút.

Mẹo: Nếu bạn cần một chức năng cho mỗi mục, hãy cân nhắc xem bạn có cần nhiều chức năng hay không. Thông thường, một hàm duy nhất lấy mục làm đối số sẽ rõ ràng hơn và tránh hoàn toàn bẫy.

Bảng tra cứu các hàm nhỏ

Lambdas nằm gọn trong một từ điển ánh xạ tên cho các hoạt động nhỏ:

ops = {
    "add": lambda a, b: a + b,
    "sub": lambda a, b: a - b,
}

ops["sub"](10, 3)   # 7

Điều này có thể thay thế một chuỗi dài if và elif. Hướng dẫn Từ điển Python bao gồm nhiều mẫu từ điển hơn và mô-đun operator đã cung cấp operator.add và operator.sub.

Giới hạn của lambdas

  • Chỉ một biểu thức. Không có phép gán với =, không có vòng lặp và không có khối try.
  • Không có câu lệnh nào. Viết lambda x: return x không thành công với SyntaxError, như thử nghiệm của chúng tôi đã xác nhận.
  • Không có gợi ý về chuỗi tài liệu hoặc loại. Các công cụ và người đọc nhận được ít trợ giúp hơn.
  • Gỡ lỗi khó hơn. Lỗi chỉ vào <lambda> thay vì tên hữu ích.

Tất nhiên, Lambdas vẫn có thể đưa ra các ngoại lệ. Việc xử lý những công việc đó cũng giống như đối với bất kỳ hàm nào, như được đề cập trong Xử lý ngoại lệ Python.

Khi nào không nên sử dụng lambda

Tình huống Lựa chọn tốt hơn
Gán nó cho một cái tên chắc chắn
Logic cần nhiều hơn một dòng chắc chắn
Chuyển đổi hoặc lọc danh sách Hiểu danh sách
Tính tổng hoặc tìm giá trị lớn nhất sum, max, min
Nhận một vật phẩm hoặc thuộc tính operator.itemgetter hoặc attrgetter
Lambda tương tự xuất hiện ở một số nơi Một hàm được đặt tên mà bạn có thể kiểm tra

Đó là điểm cuối cùng quan trọng. Việc sử dụng lại logic đáng để thử nghiệm và hàm được đặt tên sẽ dễ kiểm tra hơn nhiều, như hướng dẫn pytest của chúng tôi cho thấy.

Lời kết

Một lambda tốt phải đủ ngắn để đọc nhanh và được sử dụng một lần, thường là đối số. Các phím sắp xếp là ví dụ cổ điển. Để kiểm tra mã của riêng bạn, hãy tìm kiếm = lambda và biến chúng thành các hàm được đặt tên. Sau đó, nhìn vào bất kỳ map hoặc filter nào bằng lambda và xem liệu khả năng hiểu có đọc tốt hơn hay không.

Câu hỏi thường gặp

Hàm lambda trong Python là gì?

Đó là một hàm ẩn danh nhỏ được tạo bằng từ khóa lambda. Nó nhận các đối số và trả về giá trị của một biểu thức đơn lẻ, không có tên hoặc câu lệnh trả về.

Lambda Python có thể có nhiều dòng không?

Không. Lambda được giới hạn ở một biểu thức. Bạn có thể chia nó thành các dòng bên trong dấu ngoặc, nhưng nó vẫn không thể chứa các câu lệnh, vì vậy hãy sử dụng def cho logic phức tạp hơn.

Tôi có thể sử dụng if else trong lambda không?

Bạn có thể sử dụng biểu thức điều kiện, chẳng hạn như lambda x: “big” nếu x > 10 nếu không thì “nhỏ”. Câu lệnh if có khối không được phép.

Lambda có nhanh hơn các chức năng bình thường không?

Không có ý nghĩa. Cả hai đều tạo ra cùng một loại đối tượng hàm. Chọn giữa chúng để dễ đọc chứ không phải hiệu suất.

Tôi có nên sử dụng bản đồ với lambda hoặc hiểu danh sách không?

Hầu hết các nhà phát triển Python thích khả năng hiểu danh sách để dễ đọc. bản đồ là hợp lý khi bạn đã có một hàm được đặt tên, chẳng hạn như bản đồ (str.strip, dòng).

Tiếp tục học hỏi

Làm việc với Stack Quora

Cần trợ giúp về kiểm tra, WordPress hoặc SEO?

Chúng tôi giúp các nhóm phát triển phần mềm tốt hơn và phát triển trang web của họ. Hãy cho chúng tôi biết bạn đang làm gì và chúng tôi sẽ đề xuất bước tiếp theo rõ ràng.

Tiếp tục đọc

Thêm hướng dẫn về thử nghiệm, AI và phát triển hiện đại

Bạn thích bài viết này? Chọn một chủ đề và chuyển ngay sang phần hướng dẫn mới nhất của chúng tôi.

Trí tuệ nhân tạo

Giải thích về ảo giác AI: Tại sao các mô hình ngôn ngữ lại tạo nên mọi thứ và cách giảm thiểu nó

Ảo giác AI đã giải thích: chúng là gì, tại sao mô hình ngôn ngữ tạo ra chúng, các loại phổ biến, cách giảm thiểu chúng bằng cách căn cứ và nhắc nhở …

Đọc bài viết →
DevOps

Giải thích về các biến môi trường: Tệp .env, bí mật và cấu hình được thực hiện đúng

Các biến môi trường được giải thích bằng các ví dụ Python mà chúng tôi đã chạy: đọc và thiết lập chúng, tại sao mọi giá trị đều là một chuỗi, tệp .e…

Đọc bài viết →
Phát triển phần mềm

Giải thích về giới hạn tỷ lệ API: Thuật toán, tiêu đề và xử lý lỗi 429

Giới hạn tốc độ API được giải thích bằng mô phỏng mà chúng tôi đã chạy: nhóm mã thông báo, cửa sổ cố định, cửa sổ trượt, 429 phản hồi, tiêu đề giới …

Đọc bài viết →
Tự động hóa kiểm thử

Chế giễu bằng Python: unittest.mock, patch và những sai lầm khiến bài kiểm tra nói dối

Mô phỏng bằng Python với unittest.mock, đã được thử nghiệm: Mock và return_value, side_effect, vá lỗi nơi sử dụng tên, thông số kỹ thuật và thông số…

Đọc bài viết →
Kiểm thử phần mềm

Giải thích về phạm vi bảo hiểm của mã: Phạm vi tuyến so với chi nhánh và ý nghĩa thực sự 100%

Phạm vi bảo hiểm mã được giải thích bằng cách chạy phạm vi bảo hiểm thực tế: phạm vi bảo hiểm dòng, chi nhánh và điều kiện, đọc báo cáo, lý do tại s…

Đọc bài viết →
Cơ sở dữ liệu & SQL

DELETE vs TRUNCATE vs DROP trong SQL: Sự khác biệt, khôi phục và thời điểm sử dụng mỗi loại

DELETE vs TRUNCATE vs DROP được giải thích bằng SQL đã được thử nghiệm: mỗi loại loại bỏ, khôi phục, kích hoạt, đặt lại danh tính, tốc độ và Postgre…

Đọc bài viết →
Cơ sở dữ liệu & SQL

Giải thích về Chế độ xem SQL: Tạo, sử dụng và tránh những cạm bẫy, kèm theo ví dụ

Chế độ xem SQL được giải thích bằng các truy vấn chúng tôi đã chạy: tạo chế độ xem, kết quả trực tiếp, ẩn cột, hiệu suất, chế độ xem có thể cập nhật…

Đọc bài viết →
Phát triển phần mềm

Giao diện TypeScript so với loại: Sự khác biệt thực sự, được thử nghiệm bằng trình biên dịch

Giao diện TypeScript so với loại, được kiểm tra bằng trình biên dịch thực: cả hai có thể làm gì, chỉ một người có thể làm gì, hợp nhất khai báo, mở …

Đọc bài viết →
Phát triển phần mềm

Giải thích về Python *args và **kwargs: Hàm linh hoạt với ví dụ rõ ràng

Python *args và **kwargs được giải thích bằng mã chúng tôi đã chạy: đóng gói và giải nén, thứ tự tham số, đối số chỉ từ khóa và chỉ vị trí, trình tr…

Đọc bài viết →
Phát triển phần mềm

Hàm Lambda của Python: Cú pháp, cách sử dụng thực tế và khi nào không nên sử dụng chúng

Các hàm lambda của Python được giải thích bằng mã chúng tôi đã chạy: cú pháp, sắp xếp bằng khóa, bản đồ và bộ lọc, các phần đóng, bẫy liên kết muộn …

Đọc bài viết →
Trí tuệ nhân tạo

Đại lý AI là gì? Cách chúng hoạt động, với vòng lặp tác nhân đơn giản, bạn có thể chạy

Tác nhân AI là gì? Hướng dẫn đơn giản về vòng lặp tác nhân, công cụ, bộ nhớ và lan can, với một vòng lặp Python nhỏ mà chúng tôi đã chạy, những rủi …

Đọc bài viết →
DevOps

Giám sát và Khả năng quan sát: Sự khác biệt thực sự, với nhật ký, số liệu và dấu vết

Giải thích về giám sát và khả năng quan sát: lỗi đã biết và chưa biết, nhật ký, số liệu và dấu vết, hướng dẫn về sự cố thanh toán, tín hiệu vàng, Op…

Đọc bài viết →
DevOps

Docker Volumes vs Bind Mounts: Duy trì dữ liệu vùng chứa đúng cách

Giải thích về khối lượng Docker và liên kết gắn kết: tại sao dữ liệu vùng chứa biến mất, khối lượng được đặt tên, liên kết gắn kết, tmpfs, ví dụ về …

Đọc bài viết →
Tự động hóa kiểm thử

TDD vs BDD: Key Differences, One Feature Built Both Ways and When to Use Each

TDD và BDD được giải thích bằng một tính năng giảm giá được xây dựng theo cả hai cách: tái cấu trúc màu đỏ-xanh với mã chúng tôi đã chạy, kịch bản C…

Đọc bài viết →
Phát triển phần mềm

Git merge vs rebase: khác biệt, ví dụ và khi nào dùng cái nào

Git merge vs rebase được giải thích bằng đầu ra log thực tế, bảng so sánh, quy tắc vàng của rebase và quy trình làm việc nhóm an toàn.

Đọc bài viết →
Phát triển phần mềm

List comprehension trong Python: cú pháp, ví dụ và khi nào nên tránh

List comprehension trong Python: cú pháp, lọc dữ liệu, if-else, vòng lặp lồng nhau, thời gian đo thực tế và khi nào vòng lặp for thông thường tốt hơn.

Đọc bài viết →
Cơ sở dữ liệu & SQL

Giải thích SQL JOIN kèm ví dụ (Inner, Left, Right, Full)

Hiểu SQL JOIN từng bước với bảng và truy vấn mẫu: INNER, LEFT, RIGHT, FULL, CROSS và SELF, cùng lỗi thường gặp và mẹo hiệu năng.

Đọc bài viết →