When programming, you’ll often need to check if all the items in an iterable are truthy. Coding this functionality repeatedly can be annoying and inefficient. Luckily, Python provides the built-in all()
function to solve this problem. This function takes an iterable and checks all its items for truth value, which is handy for finding out if those items have a given property or meet a particular condition.
Python’s all()
is a powerful tool that can help you write clean, readable, and efficient code in Python.
In this tutorial, you’ll learn how to:
- Check if all the items in an iterable are truthy by using
all()
- Use
all()
with different iterable types - Combine
all()
with comprehensions and generator expressions - Distinguish between
all()
and the Booleanand
operator
To complement this knowledge, you’ll code several examples that showcase exciting use cases of all()
and highlight the many ways to use this function in Python programming.
To understand the topics in this tutorial, you should have basic knowledge of several Python concepts, such as iterable data structures, Boolean types, expressions, operators, list comprehensions, and generator expressions.
Free PDF Download: Python 3 Cheat Sheet
Evaluating the Truth Value of Items in Iterables
A pretty common problem in programming is determining if all the items in a list or array are truthy or not. For example, you may have the following list of conditions:
5 > 2
1 == 1
42 < 50
To figure out if these conditions are true, you need to iterate over them and test every condition for truthiness. In this example, you have that 5 > 2
is true, 1 == 1
is true, and 42 < 50
is also true. As a result, you can say that all these conditions are true. If at least one of the conditions were false, then you would say that not all the conditions are true.
Note that as soon as you find a falsy condition, you can stop evaluating conditions because, in that case, you already know the final result: not all are true.
To solve this problem by writing custom Python code, you can use a for
loop to iterate over each condition and evaluate it for truthiness. Your loop will iterate until it finds a falsy item, at which point it’ll stop because you already have a result:
>>> def all_true(iterable):
... for item in iterable:
... if not item:
... return False
... return True
...
This function takes an iterable as an argument. The loop iterates over the input argument while the conditional if
statement checks if any item is falsy using the not
operator. If an item is falsy, then the function immediately returns False
, signaling that not all the items are true. Otherwise, it returns True
.
This function is quite generic. It takes an iterable, which means you can pass in a list, tuple, string, dictionary, or any other iterable data structure. To check if the current item is true or false, all_true()
uses the not
operator to invert the truth value of its operand. In other words, it returns True
if its operand evaluates to false and vice versa.
Python’s Boolean operators can evaluate the truth value of expressions and objects, which guarantees that your function can take iterables containing objects, expressions, or both. For example, if you pass in an iterable of Boolean expressions, then not
just evaluates the expression and negates the result.
Here’s all_true()
in action:
>>> bool_exps = [
... 5 > 2,
... 1 == 1,
... 42 < 50,
... ]
>>> all_true(bool_exps)
True
Because all the expressions in the input iterable are true, not
negates the result, and the if
code block never runs. In that case, all_true()
returns True
.
Something similar happens when the input iterable holds Python objects and non-Boolean expressions:
>>> objects = ["Hello!", 42, {}]
>>> all_true(objects)
False
>>> general_expressions = [
... 5 ** 2,
... 42 - 3,
... int("42")
... ]
>>> all_true(general_expressions)
True
>>> empty = []
>>> all_true(empty)
True
In the first example, the input list contains regular Python objects, including a string, a number, and a dictionary. In this case, all_true()
returns False
because the dictionary is empty and evaluates to false in Python.
To perform truth value testing on objects, Python has an internal set of rules for objects that evaluate as false:
- Inherently negative constants, like
None
andFalse
- Numeric types with a zero value, like
0
,0.0
,0j
,Decimal("0")
, andFraction(0, 1)
- Empty sequences and collections, like
""
,()
,[]
,{}
,set()
, andrange(0)
- Objects that implement
.__bool__()
with a return value ofFalse
or.__len__()
with a return value of0
Any other object evaluates as true when you test it for truthiness in Python.
In the second example, the input list contains general Python expressions, such as math expressions and function calls. In this case, Python first evaluates the expression to get its resulting value, and then it checks that value for truthiness.
The third example highlights an important detail of all_true()
. When the input iterable is empty, then the for
loop doesn’t run, and the function returns True
immediately. This behavior can seem weird at first glance. However, the logic behind it is that if there are no items in the input iterable, then there’s no way to say if any items are falsy. So, the function returns True
with empty iterables.
Even though coding all_true()
is pretty straightforward in Python, it can be annoying to write this custom function every time you need its functionality. Determining if all the items in an iterable are true is such a common task in programming that Python provides the built-in all()
function for the job.
Getting Started With Python’s all()
If you check out the documentation for Python’s all()
, then you’ll note that the function is equivalent to the function you coded in the previous section. However, like all built-in functions, all()
is a C function and is optimized for performance.
Guido van Rossum proposed the all()
and any()
functions in an effort to remove functools.reduce()
and other functional tools, such as filter()
and map()
, from Python. However, the Python community wasn’t happy with removing these tools. Even so, all()
and any()
were added as built-in functions in Python 2.5, with implementations by Raymond Hettinger.
It’s possible to say that Python’s all()
performs a reduction or folding operation because it reduces an iterable of items to a single object. However, it’s not a higher-order function because it doesn’t take other functions as arguments to perform its computation. So, you can consider all()
a regular predicate or Boolean-valued function.
You can use all()
to check if all of the items in an input iterable are true. Because it’s a built-in function, you don’t need to import it. Here’s how it works:
>>> bool_exps = [
... 5 > 2,
... 1 == 1,
... 42 < 50,
... ]
>>> all(bool_exps)
True
>>> objects = ["Hello!", 42, {}]
>>> all(objects)
False
>>> general_exps = [
... 5 ** 2,
... 42 - 3,
... int("42")
... ]
>>> all(general_exps)
True
>>> empty = []
>>> all(empty)
True
These examples show that all()
works the same as your custom function, all_true()
. Internally, all()
loops over the items in the input iterable, checking their truth values. If it finds a falsy item, then it returns False
. Otherwise, it returns True
.
If you call all()
with an empty iterable, as you did in the final example above, then you get True
because there is no falsy item in an empty iterable. Note that all()
evaluates the items in the input iterable rather than the iterable itself. See Why Does all()
Return True
if the Iterable is Empty? for a more philosophical discussion about this.
To summarize the behavior of all()
, here’s its table of truth:
Condition | Result |
---|---|
All items evaluate as true. | True |
All items evaluate as false. | False |
One or more items evaluate as false. | False |
The input iterable is empty. | True |
You can run the following calls to all()
to confirm the information in this table:
>>> all([True, True, True])
True
>>> all([False, False, False])
False
>>> all([False, True, True])
False
>>> all([])
True
These examples show that all()
returns True
when all the items in the input iterable are true or when the iterable is empty. Otherwise, the function returns False
.
Just like your all_true()
function, all()
also implements what’s known as short-circuit evaluation. This kind of evaluation means that all()
will return as soon as it determines the operation’s final result.
The short-circuiting happens when the function finds a falsy item in the iterable. In that case, there’s no need to evaluate the rest of the items because the function already knows the final result. Note that this type of implementation means that you can get different behaviors when you test conditions with side effects. Consider the following example:
>>> def is_true(value):
... print("Side effect!")
... return bool(value)
...
>>> values = [0, 1]
>>> conditions = (is_true(n) for n in values)
>>> all(conditions)
Side effect!
False
>>> conditions = (is_true(n) for n in reversed(values))
>>> all(conditions)
Side effect!
Side effect!
False
The is_true()
function takes an object as an argument and returns its truth value. During the function’s execution, a side effect takes place: the function prints something to the screen.
The first instance of conditions
holds a generator expression that yields truth values after lazily evaluating each item from an input iterable, which is values
in the example. This time, all()
only evaluates the function one time because is_true(0)
returns False
. The side effect runs only once.
Now check out the second instance of conditions
. If you reverse the input iterable, then all()
evaluates both items because the call to is_true()
with 1
as an argument returns True
. The side effect runs twice.
This behavior can be a source of subtle issues, so you should avoid evaluating conditions with side effects in your code.
Finally, when it come to using the all()
function, you can say that it has at least two generic use cases. You can use all()
to check if all items in an iterable:
- Evaluate to true
- Have a given property or meet a certain condition
In the following section, you’ll learn how to use all()
with different iterable types in Python. After that, you’ll learn how to use all()
with list comprehensions and generator expressions to solve the second use case listed above.
Using all()
With Different Iterable Types
The built-in all()
function embraces Python’s duck typing style and accepts different argument types as long as they’re iterable. You can use all()
with lists, tuples, strings, dictionaries, sets, and the like.
In all cases, all()
does its work as expected, returning True
if all the items are truthy and False
otherwise. In this section, you’ll code examples using all()
with different iterable types.
Sequences
Up to this point, you’ve learned how all()
works with Python lists. In this section, you’ll learn that there’s no real difference between lists and other sequence data types, such as tuples, and range
objects. All the function needs is for the input object to be iterable.
Here are a few examples of using all()
with tuples and range
objects:
>>> # With tuples
>>> all((1, 2, 3))
True
>>> all((0, 1, 2, 3))
False
>>> all(())
True
>>> all(tuple())
True
>>> # With range objects
>>> all(range(10))
False
>>> all(range(1, 11))
True
>>> all(range(0))
True
As usual, if all the items in the input iterable are truthy, then you get True
. Otherwise, you get False
. Empty tuples and ranges produce a True
result. In the last example, calling range()
with 0
as an argument returns an empty range
object, so all()
gives you True
as a result.
You can also pass tuples containing expressions, Boolean expressions, or Python objects of any type to all()
. Go ahead and give it a try!
Dictionaries
Dictionaries are collections of key-value pairs. If you iterate through a dictionary directly, then you’ll loop over its keys automatically. In addition, you can use convenience methods to explicitly iterate dictionaries’ keys, values, and items.
Note: Using all()
with the .items()
method of a dictionary doesn’t make much sense. This method returns key-value pairs as two-items tuples, which will always evaluate to true in Python.
If you pass a dictionary directly to all()
, then the function will check the dictionary’s keys automatically:
>>> all({"gold": 1, "silver": 2, "bronze": 3})
True
>>> all({0: "zero", 1: "one", 2: "two"})
False
Because all the keys in the first dictionary are truthy, you get True
as a result. In the second dictionary, the first key is 0
, which evaluates to false. In this case, you get False
back from all()
.
If you want to get the same result as in the examples above, but with more readable and explicit code, then you can use the .keys()
method, which returns all the keys from the underlying dictionary:
>>> medals = {"gold": 1, "silver": 2, "bronze": 3}
>>> all(medals.keys())
True
>>> numbers = {0: "zero", 1: "one", 2: "two"}
>>> all(numbers.keys())
False
With .keys()
, you make it explicit that your code calls all()
to determine if all the current keys in the input dictionary are truthy.
Another common requirement is that you need to check if all the values in a given dictionary evaluate as true. In that case, you can use .values()
:
>>> monday_inventory = {"book": 2, "pencil": 5, "eraser": 1}
>>> all(monday_inventory.values())
True
>>> tuesday_inventory = {"book": 2, "pencil": 3, "eraser": 0}
>>> all(tuesday_inventory.values())
False
In these examples, you first check if there’s at least one item in your current inventory of school supplies. On Monday, all your items have at least one unit, so all()
returns True
. However, on Tuesday, the call to all()
returns False
because you’ve run out of units in at least one of your supplies, eraser
in this case.
Using all()
With Comprehensions and Generator Expressions
As you learned earlier, the second use case of Python’s all()
is to check if all the items in an iterable have a given property or meet a certain condition. To do this kind of check, you can use all()
with a list comprehension or a generator expression as an argument, depending on your needs.
The synergy you get by combining all()
with list comprehensions and generator expressions unchains the full power of this function and makes it quite valuable in your day-to-day coding.
One way to leverage this superpower of all()
is by using a predicate function that tests for the desired property. This predicate function will be the expression in the list comprehension that you’ll pass as an argument to all()
. Here’s the required syntax:
all([predicate(item) for item in iterable])
This list comprehension uses predicate()
to test each item
in iterable
for a given property. Then the call to all()
reduces the resulting list to a single True
or False
value, which tells you if all the items have the property that predicate()
defines and tests.
For example, the following code checks if all the values in a sequence are prime numbers:
>>> import math
>>> def is_prime(n):
... if n <= 1:
... return False
... for i in range(2, math.isqrt(n) + 1):
... if n % i == 0:
... return False
... return True
...
>>> numbers = [2, 3, 5, 7, 11]
>>> all([is_prime(x) for x in numbers])
True
>>> numbers = [2, 4, 6, 8, 10]
>>> all([is_prime(x) for x in numbers])
False
In this example, you combine all()
with a list comprehension. The comprehension uses the is_prime()
predicate function to test each value in numbers
for primality. The resulting list will contain Boolean values (True
or False
) for the result of every check. Then all()
gets this list as an argument and processes it to determine if all the numbers are prime or not.
Note: The is_prime()
predicate is based on an algorithm from Wikipedia’s article about primality tests.
The second use case of this magical combination, all()
plus a list comprehension, is to check if all the items in an iterable meet a given condition. Here’s the required syntax:
all([condition for item in iterable])
This call to all()
uses a list comprehension to check if all the items in iterable
satisfy the required condition
, which is generally defined in terms of an individual item
. Following this idea, here are a couple of examples that check if all the numbers in a list are greater than 0
:
>>> numbers = [1, 2, 3]
>>> all([number > 0 for number in numbers])
True
>>> numbers = [-2, -1, 0, 1, 2]
>>> all([number > 0 for number in numbers])
False
In the first example, all()
returns True
because all the numbers in the input list meet the condition of being greater than 0
. In the second example, the result is False
because the input iterable includes 0
and negative numbers.
As you already know, all()
returns True
with an empty iterable as an argument. This behavior may seem weird and can lead to wrong conclusions:
>>> numbers = []
>>> all([number < 0 for number in numbers])
True
>>> all([number == 0 for number in numbers])
True
>>> all([number > 0 for number in numbers])
True
This code shows that all the values in numbers
are less than 0
, but they’re also equal to and greater than 0
, which is impossible. The root cause of this illogical result is that all these calls to all()
evaluate empty iterables, which makes all()
return True
.
To work around this issue, you can use the built-in len()
function to get the number of items in the input iterable. If len()
returns 0
, then you can skip calling all()
to process the empty input iterable. This strategy will make your code less error-prone.
All the examples that you’ve coded in this section use a list comprehension as an argument to all()
. A list comprehension creates a complete list in memory, which can be a wasteful operation. This behavior holds especially true if you don’t need the resulting list in your code anymore, which is the typical case with all()
.
In this situation, it’s always more efficient to use all()
with a generator expression instead, especially if you’re working with a long input list. Instead of building an entire new list in memory, a generator expression will generate and yield items on demand, making your code more efficient.
The syntax to build a generator expression is almost the same as what you used for a list comprehension:
# With a predicate
all(predicate(item) for item in iterable)
# With a condition
all(condition for item in iterable)
The only difference is that a generator expression uses parentheses (()
) instead of square brackets ([]
). Because a function call will already require parentheses, you just need to remove the square brackets.
Unlike list comprehensions, generator expressions yield items on demand, making them quite efficient in terms of memory usage. Additionally, you won’t create a new list just to throw it away after all()
returns.
Comparing all()
With the and
Boolean Operator
You can roughly think of all()
as a series of items connected through the Boolean and
operator. For example, the function call all([item1, item2, ..., itemN])
is semantically equivalent to the expression item1 and item2 ... and itemN
. However, there are some tiny differences between them.
In this section, you’ll learn about those differences. The first one has to do with syntax, and the second is about the return value. Additionally, you’ll learn that both all()
and the and
operator implement short-circuit evaluation.
Understanding Syntax Differences
A call to all()
uses the same syntax as any function call in Python. You need to call the function with a pair of parentheses. In the specific case of all()
, you have to pass in an iterable of values as an argument:
>>> all([True, False])
False
The items in the input iterable can be general expressions, Boolean expressions, or Python objects of any type. Additionally, the number of items in the input iterable depends only on the amount of memory available on your system.
On the other hand, the and
operator is a binary operator that connects two operands in an expression:
>>> True and False
False
The logical and
operator takes a left and a right operand to build a compound expression. Just like with all()
, the operands in an and
expression can be general expressions, Boolean expressions, or Python objects. Finally, you can use multiple and
operators to connect any number of operands.
Returning Boolean Values vs Operands
The second and even more important difference between all()
and the and
operator is their respective return values. While all()
always returns True
or False
, the and
operator always returns one of its operands. It only returns True
or False
if the returned operand explicitly evaluates to either value:
>>> all(["Hello!", 42, {}])
False
>>> "Hello!" and 42 and {}
{}
>>> all([1, 2, 3])
True
>>> 1 and 2 and 3
3
>>> all([0, 1, 2, 3])
False
>>> 0 and 1 and 2 and 3
0
>>> all([5 > 2, 1 == 1])
True
>>> 5 > 2 and 1 == 1
True
These examples show how all()
always returns True
or False
, which is consistent with the status of a predicate function. On the other hand, and
returns the last evaluated operand. If it happens to be the last operand in an expression, then all the previous ones must have been truthy. Otherwise, and
will return the first falsy operand, indicating where the evaluation stopped.
Notice that in the final example, the and
operator returns True
because the implied operands are comparison expressions, which always return True
or False
explicitly.
This is an important difference between the all()
function and the and
operator. So, you should take it into account to prevent subtle bugs in your code. However, in Boolean contexts, such as if
statements and while
loops, this difference isn’t relevant at all.
Short-Circuiting the Evaluation
As you already learned, all()
short-circuits the evaluation of the items in the input iterable when it determines the final result. The and
operator also implements short-circuit evaluation.
The advantage of this feature is that it makes the operation efficient by skipping the remaining checks as soon as a falsy item appears.
To try out short-circuit evaluation, you can use a generator function, as in the following example:
>>> def generate_items(iterable):
... for i, item in enumerate(iterable):
... print(f"Checking item: {i}")
... yield item
...
The loop inside generate_items()
iterates over the items in iterable
, using the built-in enumerate()
function to get the index of every checked item. Then the loop prints a message identifying the checked item and yields the item at hand.
With generate_items()
in place, you can run the following code to test all()
for short-circuit evaluation:
>>> # Check both items to get the result
>>> items = generate_items([True, True])
>>> all(items)
Checking item: 0
Checking item: 1
True
>>> # Check the first item to get the result
>>> items = generate_items([False, True])
>>> all(items)
Checking item: 0
False
>>> # Still have a remaining item
>>> next(items)
Checking item: 1
True
The first call to all()
shows how the function checks both items to determine the final result. The second call confirms that all()
only checks the first item. Since this item is falsy, the function returns immediately without checking the second item. That’s why the generator still produces a second item when you call next()
.
Now you can run a similar test using the and
operator:
>>> # Check both items to get the result
>>> items = generate_items([True, True])
>>> next(items) and next(items)
Checking item: 0
Checking item: 1
True
>>> # Check the first item to get the result
>>> items = generate_items([False, True])
>>> next(items) and next(items)
Checking item: 0
False
>>> # Still have a remaining item
>>> next(items)
Checking item: 1
True
The first and
expression evaluates both operands to get the final result. The second and
expression only evaluates the first operand to determine the result. The call to next()
with items
as an argument shows that the generator function still yields a remaining item.
Putting all()
Into Action: Practical Examples
So far, you’ve learned the basics of Python’s all()
. You’ve learned to use it with sequences, dictionaries, list comprehensions, and generator expressions. Additionally, you’ve learned about the differences and similarities between this built-in function and the logical and
operator.
In this section, you’ll code a series of practical examples that will help you assess how useful all()
can be while you’re programming with Python. So, stay tuned and enjoy your coding!
Improving the Readability of Long Compound Conditions
One interesting feature of all()
is how this function can improve the code’s readability when you’re working with long compound Boolean expressions based on the and
operator.
For example, say you need to validate the user’s input in a piece of code. For the input to be valid, it should be an integer number between 0
and 100
that’s also an even number. To check all these conditions, you can use the following if
statement:
>>> x = 42
>>> if isinstance(x, int) and 0 <= x <= 100 and x % 2 == 0:
... print("Valid input")
... else:
... print("Invalid input")
...
Valid input
The if
condition consists of a call to isinstance()
that checks if the input is an integer number, a chained comparison expression that checks if the number is between 0
and 100
, and an expression that checks if the input value is an even number.
Even though this code works, the condition is quite long, which makes it difficult to parse and understand. Additionally, if you need to add more validation checks in future updates, then the condition will get longer and more complicated. It’d also require some code formatting.
To improve the readability of this conditional, you can use all()
, like in the following code:
>>> x = 42
>>> validation_conditions = (
... isinstance(x, int),
... 0 <= x <= 100,
... x % 2 == 0,
... )
>>> if all(validation_conditions):
... print("Valid input")
... else:
... print("Invalid input")
...
Valid input
In this example, all the validation conditions live in a tuple with a descriptive name. Using this technique has an additional advantage: if you ever need to add a new validation condition, then you just have to add a new line to your validation_conditions
tuple. Note that now your if
statement holds a pretty readable, explicit, and concise expression based on all()
.
In real life, a validation strategy typically would allow you to reuse your validation code. For example, instead of specifying plain conditions that evaluate only once, you can code reusable validation functions:
>>> def is_integer(x):
... return isinstance(x, int)
...
>>> def is_between(a=0, b=100):
... return lambda x: a <= x <= b
...
>>> def is_even(x):
... return x % 2 == 0
...
>>> validation_conditions = (
... is_integer,
... is_between(0, 100),
... is_even,
... )
>>> for x in (4.2, -42, 142, 43, 42):
... print(f"Is {x} valid?", end=" ")
... print(all(condition(x) for condition in validation_conditions))
...
Is 4.2 valid? False
Is -42 valid? False
Is 142 valid? False
Is 43 valid? False
Is 42 valid? True
In this example, you have three functions that check your three original conditions in a reusable way. Then you redefine your tuple of validation conditions using the functions you just coded. The final for
loop shows how you can reuse these functions to validate several input objects using all()
.
Validating Iterables of Numeric Values
Another interesting use case of all()
is to check if all the numeric values in an iterable are in a given interval. Here are a few examples of how to do this for different conditions and with the help of a generator expression:
>>> numbers = [10, 5, 6, 4, 7, 8, 20]
>>> # From 0 to 20 (Both included)
>>> all(0 <= x <= 20 for x in numbers)
True
>>> # From 0 to 20 (Both excluded)
>>> all(0 < x < 20 for x in numbers)
False
>>> # From 0 to 20 (integers only)
>>> all(x in range(21) for x in numbers)
True
>>> # All greater than 0
>>> all(x > 0 for x in numbers)
True
These examples show how you can build generator expressions to check if all the values in an iterable of numbers are in a given interval.
The technique in the examples above allows a lot of flexibility. You can tweak the condition and use all()
to run all kinds of checks on the target iterable.
Validating Strings and Iterables of Strings
The built-in str
type implements several predicate string methods that can be useful when you need to validate iterables of strings and individual characters in a given string.
For example, with those methods, you can check if a string is a valid decimal number, if it’s an alphanumeric character, or if it’s a valid ASCII character.
Here are a few examples of using string methods in your code:
>>> numbers = ["1", "2", "3.0"]
>>> all(number.isdecimal() for number in numbers)
True
>>> chars = "abcxyz123"
>>> all(char.isalnum() for char in chars)
True
>>> all(char.isalpha() for char in chars)
False
>>> all(char.isascii() for char in chars)
True
>>> all(char.islower() for char in chars)
False
>>> all(char.isnumeric() for char in chars)
False
>>> all(char.isprintable() for char in chars)
True
Each of these .is*()
methods checks a specific property on the underlying string. You can take advantage of these and several other string methods to validate items in an iterable of strings as well as individual characters in a given string.
Removing Rows With Empty Fields From Tabular Data
When you’re working with tabular data, you may face the issue of having empty fields. Cleaning the rows containing empty fields may be a requirement for you. If that’s the case, then you can use all()
and filter()
to extract the rows that have data in all their fields.
The built-in filter()
function takes a function object and an iterable as arguments. Typically, you’ll use a predicate function as the first argument to filter()
. A call to filter()
applies the predicate to every item in the iterable and returns an iterator with the items that make the predicate return True
.
You can use all()
as the predicate in a filter()
call. This way, you can process lists of lists, which can be useful when you’re working with tabular data.
For a concrete example, say you have a CSV file with data about your company’s employees:
name,job,email
"Linda","Technical Lead",""
"Joe","Senior Web Developer","joe@example.com"
"Lara","Project Manager","lara@example.com"
"David","","david@example.com"
"Jane","Senior Python Developer","jane@example.com"
With a quick look at this file, you’ll note that some rows hold empty fields. For example, the first row doesn’t have an email, and the fourth row doesn’t provide a position or role. You need to clean up the data by removing rows containing empty fields.
Here’s how you can satisfy that requirement by using all()
as the predicate in a filter()
call:
>>> import csv
>>> from pprint import pprint
>>> with open("employees.csv", "r") as csv_file:
... raw_data = list(csv.reader(csv_file))
...
>>> # Before cleaning
>>> pprint(raw_data)
[['name', 'job', 'email'],
['Linda', 'Technical Lead', ''],
['Joe', 'Senior Web Developer', 'joe@example.com'],
['Lara', 'Project Manager', 'lara@example.com'],
['David', '', 'david@example.com'],
['Jane', 'Senior Python Developer', 'jane@example.com']]
>>> clean_data = list(filter(all, raw_data))
>>> # After cleaning
>>> pprint(clean_data)
[['name', 'job', 'email'],
['Joe', 'Senior Web Developer', 'joe@example.com'],
['Lara', 'Project Manager', 'lara@example.com'],
['Jane', 'Senior Python Developer', 'jane@example.com']]
In this example, you first load the content of the target CSV file into raw_data
by using the csv
module from the Python standard library. The call to the pprint()
function shows that the data contains rows with empty fields. Then you clean up the data with filter()
and all()
.
Note: If you don’t feel comfortable using filter()
, then you can replace it with a list comprehension.
Go ahead and run the following line of code instead:
>>> clean_data = [row for row in raw_data if all(row)]
Once you have your list of clean data, then you can run the for
loop again to check if everything worked okay.
How do the filter()
and all()
functions work together to execute the task? Well, if all()
finds an empty field in a row, then it returns False
. With that result, filter()
won’t include that row in the final data. To make sure that this technique works, you can call pprint()
with the clean data as an argument.
Comparing Custom Data Structures
As another example of how to use all()
, say you need to create a custom list-like class that allows you to check if all its values are greater than a specific value.
To create this custom class, you can subclass UserList
from the collections
module and then override the special method called .__gt__()
. Overriding this method allows you to overload the greater than (>
) operator, providing a custom behavior for it:
>>> from collections import UserList
>>> class ComparableList(UserList):
... def __gt__(self, threshold):
... return all(x > threshold for x in self)
...
>>> numbers = ComparableList([1, 2, 3])
>>> numbers > 0
True
>>> numbers > 5
False
In .__gt__()
, you use all()
to check if all the numbers in the current list are greater than a specific threshold
value that should come from the user.
The comparison expressions at the end of this code snippet show how to use your custom list and how it behaves with the greater than (>
) operator. In the first expression, all the values in the list are greater than 0
, so the result is True
. In the second expression, all the numbers are less than 5
, which results in a False
outcome.
Partially Emulating Python’s zip()
Function
Python’s built-in zip()
function is useful for looping over multiple iterables in parallel. This function takes a given number of iterables (N) as arguments and aggregates elements from each of them into N-items tuples. In this example, you’ll learn how to use all()
to partially simulate this functionality.
To better understand the challenge, check out the basics of what zip()
does:
>>> numbers = zip(["one", "two"], [1, 2])
>>> list(numbers)
[('one', 1), ('two', 2)]
In this example, you pass two lists as arguments to zip()
. The function returns an iterator that yields tuples of two items each, which you can confirm by calling list()
with the resulting iterator as an argument.
Here’s a function that simulates this functionality:
>>> def emulated_zip(*iterables):
... lists = [list(iterable) for iterable in iterables]
... while all(lists):
... yield tuple(current_list.pop(0) for current_list in lists)
...
>>> numbers = emulated_zip(["one", "two"], [1, 2])
>>> list(numbers)
[('one', 1), ('two', 2)]
Your emulated_zip()
function can take a variable number of arguments consisting of iterable objects. The first line inside the function uses a list comprehension to convert each input iterable into a Python list so that you can later use its .pop()
method. The loop condition relies on all()
to check if all the input lists contain at least one item.
In every iteration, the yield
statement returns a tuple containing one item from each input list. The call to .pop()
with 0
as an argument retrieves and removes the first item from each list.
Once the loop iterates enough times that .pop()
removes all the items from either list, the condition becomes false, and the function terminates. The loop ends when the shortest iterable gets exhausted, truncating longer iterables. This behavior is consistent with the default behavior of zip()
.
Note that your function only partially emulates the built-in zip()
function because yours doesn’t take the strict
argument. This argument was added in Python 3.10 as a safe way to handle iterables of unequal length.
Conclusion
Now you know how to check if all the items in an existing iterable are truthy by using Python’s built-in all()
function. You also know how to use this function to find out if the items in an iterable meet a given condition or have a specific property.
With this knowledge, you’re now able to write more readable and efficient Python code.
In this tutorial, you learned:
- How to use Python’s
all()
to check if all the items in an iterable are truthy - How
all()
works with different iterable types - How to combine
all()
with comprehensions and generator expressions - What makes
all()
different from and similar to theand
operator
Additionally, you coded several practical examples that helped you understand how powerful all()
can be and what some of its most common use cases in Python programming are.
Free PDF Download: Python 3 Cheat Sheet