Hàm any() của Python làm gì?
Hàm any() là một trong các hàm dựng sẵn. Nó nhận vào một iterable như list hoặc tuple, và trả về True nếu có ít nhất một giá trị trong iterable là truthy. Một giá trị truthy sẽ được đánh giá là True khi ép sang Boolean bằng bool(). Nếu tất cả giá trị trong iterable đều là falsy, any() trả về False:
print(any([True, False, False, True]))
print(any([False, False, False, False]))
print(any([0, 0, 5, 0]))
True
False
True
Iterable có thể chứa các giá trị Boolean hoặc các đối tượng khác vì mọi đối tượng đều được đánh giá là True hoặc False khi ép sang Boolean. Ở ví dụ thứ ba, list gồm bốn số nguyên. Số nguyên 0 là falsy, còn mọi số khác 0 là truthy. Để hiểu rõ hơn về khác biệt giữa giá trị truthy và falsy, hãy đọc bài viết này về toán tử logic trong Python.
Nếu iterable rỗng, any() trả về False vì không có giá trị truthy nào trong một iterable rỗng:
print(any([]))
False
Phần tiếp theo sẽ đi sâu hơn vào cách any() hoạt động.
any() hoạt động như thế nào?
Hàm dựng sẵn any() nhận bất kỳ iterable nào làm đối số. Iterable là bất kỳ cấu trúc dữ liệu nào mà Python có thể lặp qua.
Xem xét tuple sau:
an_iterable = ("", 0.0, "DataCamp", False, [])
Tuple này bao gồm nhiều đối tượng với các kiểu khác nhau. Một số trong đó là falsy:
- Chuỗi rỗng
"" - Số thực
0.0 - Giá trị Boolean
False - List rỗng
[]
Các đối tượng này là falsy vì chúng được đánh giá là False khi truyền vào bool().
Chuỗi không rỗng "DataCamp" là truthy.
Một cách đơn giản để kiểm tra xem có ít nhất một phần tử là truthy hay không là dùng vòng lặp for:
def check_if_contains_truthy(data):
output = False
for item in data:
if item:
output = True
return output
print(check_if_contains_truthy(an_iterable))
True
Tuy nhiên, cách này không hiệu quả vì hàm chỉ cần kiểm tra xem có ít nhất một giá trị truthy hay không. Khi đã tìm thấy một giá trị truthy, không cần tiếp tục kiểm tra các phần tử còn lại của iterable nữa. Có thể sửa hàm để trả về ngay khi gặp giá trị truthy đầu tiên:
def check_if_contains_truthy(data):
for item in data:
if item:
return True
return False
print(check_if_contains_truthy(an_iterable))
True
Câu lệnh return dừng việc thực thi của hàm. Do đó, khi hàm tìm thấy giá trị truthy đầu tiên, nó trả về True và không tiếp tục duyệt qua iterable nữa. Hàm chỉ trả về False nếu vòng lặp for đã duyệt hết các phần tử trong iterable mà không có phần tử nào truthy.
Hàm dựng sẵn any() tuân theo một mẫu tương tự và "short-circuit" khi gặp giá trị truthy đầu tiên. Cách đánh giá lười (lazy evaluation) này tránh các thao tác không cần thiết, giúp cải thiện hiệu năng. any() của Python là phiên bản hiệu quả hơn của hàm ở trên. Hiệu quả được cải thiện này được xác nhận bằng cách dùng hàm timeit() từ mô-đun timeit, hàm này đo thời gian Python cần để thực thi một câu lệnh:
from timeit import timeit
print("Execution time for 'check_if_contains_truthy()'")
print(
timeit(
"check_if_contains_truthy(an_iterable)",
number=10_000_000,
globals=globals(),
)
)
print("Execution time for 'any()'")
print(
timeit(
"any(an_iterable)",
number=10_000_000,
globals=globals(),
)
)
Execution time for 'check_if_contains_truthy()'
0.6335119580035098
Execution time for 'any()'
0.39488654200249584
Đối số đầu tiên của hàm timeit() là một chuỗi chứa câu lệnh cần thực thi. Đối số thứ hai xác định số lần chạy câu lệnh. Trong ví dụ này, cả hai câu lệnh được chạy 10.000.000 lần để có số đo thời gian có ý nghĩa. Đối số cuối cùng truyền các biến toàn cục vào hàm timeit().
Hàm any() của Python nhanh hơn check_if_contains_truthy(). Dùng any() để tìm xem một iterable có ít nhất một giá trị truthy hay không vừa "Pythonic" vừa hiệu quả hơn so với dùng vòng lặp for.
Các tình huống sử dụng any()
Hãy cùng xem một số tình huống sử dụng hàm any() của Python.
Kiểm tra xem có ít nhất một đầu vào người dùng hợp lệ
Giả sử có một loạt đầu vào người dùng được thu thập trong list hoặc tuple. Chương trình có thể cần kiểm tra xem có ít nhất một đầu vào hợp lệ hay không, chẳng hạn như một chuỗi không rỗng:
user_inputs = ["", "10.99", ""]
if any(user_inputs):
print("At least one valid input present")
# Rest of code...
else:
print("There are no valid inputs")
At least one valid input present
Vì một trong các chuỗi không rỗng, any() trả về True và đoạn mã trong mệnh đề if được thực thi.
Kiểm tra xem có ít nhất một tệp tồn tại
Hàm dựng sẵn any() có thể dùng để kiểm tra xem có ít nhất một tệp trong danh sách tên tệp tồn tại trong một thư mục hay không:
from pathlib import Path
files = ["article.md", "use_any.py", "scratch.py", "test_file.txt"]
cwd = Path.cwd()
# Create a test file to test code
Path("test_file.txt").write_text("This is a test file")
if any(Path(file).exists() for file in files):
print("At least one of the files exists")
# Rest of code…
else:
print("None of the files exist")
At least one of the files exists
Đoạn mã lấy thư mục làm việc hiện tại bằng mô-đun pathlib và Path.cwd(). Nó tạo một tệp tên là test_file.txt trong thư mục làm việc để có thể dễ dàng kiểm tra mã này. Hàm any() của Python được dùng để kiểm tra xem có ít nhất một tên tệp tồn tại trong thư mục làm việc hiện tại hay không.
Lọc mục từ một iterable
Hàm dựng sẵn any() cũng có thể dùng với biểu thức generator làm đối số và lọc các mục từ một iterable. Trong ví dụ này, any() tìm kiếm ít nhất một mục trong danh sách các dict đại diện cho một người có tuổi dưới 18:
records = [
{"name": "Sarah", "age": 23},
{"name": "Jake", "age": 30},
{"name": "Paul", "age": 17},
]
if any(record["age"] < 18 for record in records):
print("There's at least one minor.")
else:
print("All records are adults.")
There's at least one minor.
Biểu thức generator trả ra True hoặc False tùy theo giá trị ứng với khóa "age" của từng dict. Biểu thức generator có thể dùng trong any() vì nó là iterable.
Xem lại cơ chế đánh giá lười trong any() của Python
Ví dụ trước cũng có thể minh họa rằng any() được đánh giá một cách lười biếng (lazily). Xem xét sửa đổi sau đối với danh sách dict:
records = [
{"name": "Sarah", "age": 23},
{"name": "Jake", "age": 30},
{"name": "Paul", "age": 17},
{"name": "Jill"},
]
if any(record["age"] < 18 for record in records):
print("There's at least one minor.")
else:
print("All records are adults.")
There's at least one minor.
Dict thứ tư trong records không chứa mục với khóa "age". Tuy nhiên, mã không phát sinh lỗi khi cố lấy giá trị tương ứng với "age" cho mục này vì any() đã tìm được một giá trị truthy từ trước. Hàm sẽ short-circuit khi gặp giá trị truthy đầu tiên.
Mã sẽ phát sinh KeyError nếu dict bị thiếu khóa "age" xuất hiện trước bất kỳ mục nào có tuổi dưới 18:
records = [
{"name": "Jill"},
{"name": "Sarah", "age": 23},
{"name": "Jake", "age": 30},
{"name": "Paul", "age": 17},
]
if any(record["age"] < 18 for record in records):
print("There's at least one minor.")
else:
print("All records are adults.")
Traceback (most recent call last):
...
if any(record["age"] < 18 for record in records):
~~~~~^^^^^^
KeyError: 'age'
Ví dụ này nhằm minh họa hành vi short-circuit khi dùng any() của Python. Có một cách khác nếu bạn không muốn mã phát sinh ngoại lệ cho các mục không có khóa "age". Ta có thể dùng phương thức dict .get() với giá trị mặc định thay vì truy cập giá trị dict bằng cú pháp ngoặc vuông. Câu lệnh if có thể được thay bằng phiên bản sau nếu hành vi mặc định là giả định rằng các mục không có tuổi thì không phải là trẻ vị thành niên:
if any(record.get("age", 18) < 18 for record in records):
# ...
Nếu mã cần giả định rằng mọi mục không có tuổi đều là trẻ vị thành niên, giá trị mặc định phải là một giá trị nhỏ hơn 18.
Python: any() so với all()
Hàm any() của Python có một hàm đi kèm, là all(). Hàm dựng sẵn này cũng nhận một iterable và trả về True nếu tất cả các mục trong iterable đều là truthy.
Xem lại ví dụ trước trong hướng dẫn này để kiểm tra tính hợp lệ của đầu vào người dùng. any() của Python hữu ích nếu ứng dụng yêu cầu có ít nhất một đầu vào hợp lệ. Tuy nhiên, có thể dùng all() nếu tất cả các đầu vào người dùng đều phải hợp lệ:
user_inputs = ["", "10.99", ""]
if any(user_inputs):
print("At least one valid input present")
# Rest of code...
else:
print("There are no valid inputs")
if all(user_inputs):
print("All inputs are valid")
# Rest of code...
else:
print("Not all inputs are valid")
At least one valid input present
Not all inputs are valid
Tuy nhiên, nếu tất cả các chuỗi trong đầu vào người dùng đều không rỗng, all() trả về True:
user_inputs = ["5.99", "10.99", "19.99"]
# …
At least one valid input present
All inputs are valid
Tương tự any(), hàm dựng sẵn all() cũng được đánh giá lười. Hàm sẽ short-circuit khi gặp giá trị falsy đầu tiên.
Kết luận
Hàm any() của Python xác định xem có mục nào trong một iterable là truthy hay không. Hàm trả về True nếu có ít nhất một mục trong iterable là True hoặc được đánh giá là True khi ép sang Boolean. Mặc dù có thể đạt cùng kết quả bằng vòng lặp, hàm dựng sẵn này mang lại giải pháp dễ đọc và hiệu quả hơn.
Tôi học Vật lý và Toán ở bậc đại học tại Đại học Malta. Sau đó, tôi chuyển đến London và lấy bằng Tiến sĩ Vật lý tại Imperial College. Tôi nghiên cứu các kỹ thuật quang học mới để chụp ảnh võng mạc người. Hiện nay, tôi tập trung vào việc viết về Python, truyền đạt về Python và giảng dạy Python.

Một yêu cầu phổ biến trong các chương trình Python là kiểm tra xem có ít nhất một phần tử của cấu trúc dữ liệu là
True.Mặc dù có thể viết một vòng lặp để duyệt qua một iterable và kiểm tra từng mục đánh giá là
TruehayFalse, hàmany()của Python là cách hiệu quả hơn và "Pythonic" hơn để đạt được kết quả này.Hướng dẫn này khám phá hàm dựng sẵn
any()của Python và đưa ra một số ví dụ cũng như các tình huống sử dụng của hàm này.