Câu 1Code này in gì?nums = [1, 2, 3]
print(list(map(lambda x: x + 10, nums)))
map() — Áp dụng một hàm cho mọi phần tử của list cùng lúc
Học hàm map() trong Python để áp dụng cùng một hàm cho mọi phần tử của list, kết hợp tự nhiên với lambda.
Trong bài trước về decorator, bạn đã thấy cách bọc hành vi bổ sung quanh một hàm. Lần này, bạn sẽ chuyển hướng và xem hàm built-in map() — công cụ bạn với tới khi muốn áp dụng cùng một hàm cho mọi phần tử của list cùng lúc.
map() kết hợp tự nhiên với lambda, và cơ chế bên dưới tương tự list comprehension. Ngày nay, comprehension thường là lựa chọn được khuyên dùng hơn map().
map() là gì — Hàm bậc cao đụng tới mọi phần tử
map(function, iterable) áp dụng hàm của tham số đầu tiên cho mọi phần tử của tham số thứ hai (một list, tuple, v.v.) và trả về một đối tượng map cho phép bạn lấy ra kết quả từng cái một. Bạn có thể lặp nó với for, hoặc bọc trong list() để vật chất hóa toàn bộ thành list.
Vì tham số đầu tiên của nó là một hàm, chính map() được tính là hàm bậc cao.
map. Bọc trong list() để vật chất hóa nội dung.numbers = [1, 2, 3, 4, 5]
squared = map(lambda x: x ** 2, numbers)
print(type(squared)) # <class 'map'>
print(squared) # <map object at 0x...>
# Lấy giá trị bằng list()
print(list(squared)) # [1, 4, 9, 16, 25]
# Hàm built-in cũng dùng được (chuyển list chuỗi thành int)
str_nums = ["10", "20", "30"]
print(list(map(int, str_nums))) # [10, 20, 30]
Đối tượng map dùng một lần
Giá trị trả về của map() là một iterator — cùng loại bạn nhận từ generator — và một khi bạn đã đi qua, nó rỗng. Gọi list(squared) lần thứ hai và bạn sẽ nhận []. Nếu cần dùng kết quả nhiều hơn một lần, làm list(map(...)) trước và làm việc với list.
Truyền nhiều iterable cùng lúc
Từ tham số thứ hai trở đi, map() chấp nhận nhiều iterable. Trong trường hợp đó, hàm của tham số đầu cần chấp nhận một phần tử từ mỗi iterable ở vị trí khớp. Viết map(function, A, B) và hàm được áp dụng cho cặp A[0] và B[0], rồi A[1] và B[1], v.v.
Ví dụ, để nhân hai list số theo phần tử, map(lambda a, b: a * b, A, B) cho bạn list các tích từng cặp.
A = [1, 2, 3]
B = [10, 20, 30]
# Nhân các phần tử cùng index
print(list(map(lambda a, b: a * b, A, B))) # [10, 40, 90]
# Tương tự với ba iterable
def calculate(x, y, op):
return x + y if op == "plus" else x - y
xs = [10, 20, 30]
ys = [3, 3, 3]
ops = ["plus", "minus", "plus"]
print(list(map(calculate, xs, ys, ops))) # [13, 17, 33]
A và B ở cùng index được ghép cặp và đưa vào lambda lambda a, b: a * b.Độ dài lệch nhau dừng ở cái ngắn nhất
Khi các iterable bạn truyền có độ dài khác nhau, map() dừng ở cái ngắn nhất. Ví dụ, map(f, [1, 2, 3, 4], [10, 20]) chỉ chạy hai lần. Nếu muốn căn chỉnh rõ ràng, kiểm tra độ dài trước, hoặc kết hợp map() với `zip()` tùy nhu cầu.
map() vs List Comprehension — Bạn nên dùng cái nào?
Hầu như mọi thứ map() làm được, list comprehension cũng làm được. Tài liệu chính thức của Python và sách như Fluent Python khuyên ưu tiên comprehension trong code mới, và trong Python hiện đại, comprehension là dạng chuẩn.
map() từng là mặc định trong code cũ, nhưng vai trò của nó đã thu hẹp lại còn các trường hợp bạn có thể trao một tên hàm có sẵn mà không cần viết lambda (nghĩ map(int, str_nums)). Hãy xếp các khác biệt cạnh nhau.
| Mục tiêu | Với map() | Với comprehension |
|---|---|---|
| Bình phương mọi phần tử | list(map(lambda x: x ** 2, nums)) | [x ** 2 for x in nums] |
| Chuyển str thành int | list(map(int, str_nums)) | [int(s) for s in str_nums] |
| Hai list cùng lúc | list(map(f, A, B)) | [f(a, b) for a, b in zip(A, B)] |
nums = [1, 2, 3, 4, 5]
# Phiên bản map()
print(list(map(lambda x: x ** 2, nums))) # [1, 4, 9, 16, 25]
# Phiên bản comprehension (được ưu tiên)
print([x ** 2 for x in nums]) # [1, 4, 9, 16, 25]
# Khi truyền tên hàm trực tiếp được, map() trông sạch hơn
str_nums = ["10", "20", "30"]
print(list(map(int, str_nums))) # [10, 20, 30]
print([int(s) for s in str_nums]) # [10, 20, 30]
# Khi lọc, comprehension cô đọng hơn nhiều
print([x for x in nums if x % 2 == 0]) # [2, 4]
Khi do dự, với tay tới comprehension
Dù bạn muốn biến đổi, lọc, hay làm cả hai, comprehension cho phép bạn viết tất cả tự nhiên trong cùng cặp ngoặc. Nếu bạn cam kết dùng map() chỉ khi trao một tên hàm có sẵn nguyên dạng, code của bạn vẫn nhất quán. Nó nhẹ hơn cho cả người viết và người đọc, nên ưu tiên comprehension trong code mới.
Kiểm tra kiến thức
Hãy trả lời từng câu hỏi một.
Câu 2Comprehension nào tạo cùng kết quả với list(map(int, ["1", "2", "3"]))?
Câu 3Phát biểu nào về giá trị trả về của map() là đúng?