Advanced Tools in Python - Zip, Enumerate, Spreading, Packing, and Unpacking Arguments
Day 17 of the Python course dives into advanced tools for handling arguments, collections, and iteration. In this post, I’ll explain how these tools work with real-world examples and share how I’m learning to master them. This day has been split over two posts, with the first half discussing
Advanced Tools in Python - Zip(), Enumerate(), Spreading, Packing, and Unpacking Arguments
Throughout this series, I have previously posted on some of these functions and their abilities. While it was subtle information, it now needs to be elaborated on as I begin to learn more advanced or intermediate functions in Python.
Day 17 of this course has been split into 2 parts, one for Error Handling and this one for Advanced features.
In this post, I’ll walk you through each of these advanced tools—packing and unpacking arguments, spreading sequences, enumerating collections, and zipping iterables—with real-world examples to demonstrate how each works.
Packing and Unpacking Arguments
By now, I have already familiarised myself with these concepts; the only difference now is that we’ll be practising them on functions. The term packing and unpacking is derived from the use of being able to take a collection of data and place them in another or vice versa.
Unpacking Arguments
Unpacking is the process of taking a collection (like a list, tuple, or dictionary) and breaking it into individual elements, which are then passed as arguments to a function’s parameters.
Example 1: Unpacking a List into Arguments
For this example, we will use the sum() function to calculate our return value. We’ll have several parameters so that it can take a specific number of arguments to then use in the sum() to produce our total.
We’ll then use the unpacking feature to pass our arguments in as values from a separate data source (i.e. list).
1
2
3
4
5
6
def summation(a, b, c, d, e): # Our parameters
return sum(a, b, c, d, e) # sum function
lst = [1, 2, 3, 4, 5] # List with items
print(summation(*lst)) # Unpack the list into arguments which match the parameters.
# Output: 15
*lst unpacks the list items into individual arguments. Then the sum() function performs its calculation to provide us with a result.
This is a more efficient way to pass multiple arguments into a function if you already have them in a collection.
Example 2: Unpacking a Dictionary into Arguments
If you have a dictionary where the keys match the parameter names of a function, you can use ** to unpack the dictionary.
1
2
3
4
5
6
def greeting(name, country, age): # parameter names == dictionary keys
return f"Hi, I'm {name}, from {country}, and I'm {age} years old."
dct = {"name": "Sheikh", "country": "UK", "age": 30} # our data source
print(greeting(**dct)) # Unpacking the dictionary
# Output: "Hi, I'm Sheikh, from UK, and I'm 30 years old."
**dct unpacks the dictionary dct into keyword arguments. The keys of the dictionary match the parameter names, and the values are passed as arguments.
Tip: Keep in mind that so far we have been using the exact number of items to parameters which is making this work well. We’ll later discover how we can use the same function on an arbitrary or random number of parameters/arguments.
Packing Arguments
Packing is the opposite of unpacking. Think about having an array of an arbitrary number of elements that you want to place inside parameters or arguments. You can use *args (for positional arguments) or **kwargs (for keyword arguments) to pack data into collections that will be handled inside the function.
Example 1: Packing with *args
If you want to pass any number of arguments to a function, you can use *args to pack them into a tuple or any collection data type.
1
2
3
4
5
6
7
def sum_all(*args): # Takes a infinite number of *positional* arguments
return sum(args) # Calculates the sum of them all
print(sum_all(1, 2, 3, 4, 5)) # Only provided 5 arguments
# Output: 15
print(sum_all(10, 20, 30)) # Only provided 3 arguments
# Output: 60
With this example our *args parameter recognises all the parameters as its arguments to use within the function. While this is useful, we should also keep in mind that the function is using them all for the same process, adding them all together using the sum() function.
Example 2: Packing with **kwargs
You can use **kwargs to pack keyword arguments into a dictionary.
1
2
3
4
5
6
7
8
9
10
11
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Sheikh", country="UK", age=30)
# Output:
# name: Sheikh
# country: UK
# age: 30
**kwargs collects all keyword arguments into a dictionary, which can be iterated over to access each key-value pair.
Tip: Think of
*being for one data to be stored recursively as different arguments and**for two pieces of data to be stored.
Spreading in Python
This is very similar to unpacking and packing; the only real difference is that you’ll be able to group different elements into different variables, creating sub-collections of data from an original data source. You can “spread” the elements of a collection into separate variables or create new collections by combining parts of existing ones.
Example 1: Unpacking into Multiple Variables
You can use the * operator to split a sequence into multiple variables.
1
2
3
4
5
6
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
first, *middle, last = lst
print("First:", first) # Output: 1
print("Middle:", middle) # Output: [2, 3, 4, 5, 6, 7, 8, 9]
print("Last:", last) # Output: 10
*middle captures all the middle elements into a list.
first gets the first element, and last gets the last element.
Example 2: Splitting a List into Two Parts
You can also use the * operator to split a list into two parts.
1
2
3
4
5
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
*half1, *half2 = lst
print("First Half:", half1) # Output: [1, 2, 3, 4, 5]
print("Second Half:", half2) # Output: [6, 7, 8, 9, 10]
This will split the list into two halves using the * operator. The process of packing involves either combining multiple values into a collection (i.e. variables) and passing that collection into a function as an argument, and breaking down a collection (i.e. list) into individual arguments (i.e parameters or variables) to be passed into a function is called unpacking.
Enumerating Collections
In my prior posts, I’ve already explained how items are stored in lists using indices1 or hash values2. I’ve also briefly explained that you can bring those values back by using either .index() or .hash() to get these for each item in the data source.
Python’s built-in enumerate() function makes this easy. It allows you to loop through a collection and get both the index and the item - This doesn’t work with hash values.
Example 1: Basic Use of enumerate()
Let’s see how enumerate() works when iterating over a list:
1
2
3
4
5
6
7
8
9
10
lst = ['apple', 'banana', 'cherry', 'dates']
for index, item in enumerate(lst):
print(f"Index {index}: {item}")
# Output:
# Index 0: apple
# Index 1: banana
# Index 2: cherry
# Index 3: dates
enumerate() returns both the index and the value for each item in the collection, allowing us to track positions easily.
Example 2: Finding an Item with enumerate()
You can also use enumerate() to find the index of a specific item.
1
2
3
4
5
6
7
8
countries = ['USA', 'Finland', 'Sweden', 'Norway', 'Denmark']
for index, country in enumerate(countries):
if country == 'Finland':
print(f"Found Finland at index {index}")
break
# Output:
# Found Finland at index 1
This example uses enumerate() to find the index of ‘Finland’ in the list of countries, and break stops the loop once it’s found.
Zip: Combining Two Lists into a Collection
The zip() function is a versatile tool that allows you to combine two or more iterables into a collection of pairs. It’s particularly useful for creating dictionaries or combining related data from multiple lists.
Example 1: Combining Two Lists into Key-Value Pairs
Let’s say we have two lists, one with fruits and one with vegetables, and we want to combine them into key, value pairs (making a dictionary):
1
2
3
4
5
6
7
8
9
10
11
12
13
fruits = ['banana', 'orange', 'mango', 'lemon', 'lime']
vegetables = ['tomato', 'potato', 'cabbage', 'onion', 'carrot']
combined = [{'fruit': f, 'veg': v} for f, v in zip(fruits, vegetables)]
# Using list comprehension to make this function instead....
print(combined)
# Output:
# [{'fruit': 'banana', 'veg': 'tomato'},
# {'fruit': 'orange', 'veg': 'potato'},
# {'fruit': 'mango', 'veg': 'cabbage'},
# {'fruit': 'lemon', 'veg': 'onion'},
# {'fruit': 'lime', 'veg': 'carrot'}]
zip(fruits, vegetables) pairs each fruit with the corresponding vegetable, and the dict inside the list comprehension turns them into dictionaries.
Example 2: Using zip() with More Than Two Lists
You can also zip together more than two lists to combine them into tuples of corresponding items.
1
2
3
4
5
6
7
8
9
names = ['Alice', 'Bob', 'Charlie']
ages = [24, 30, 22]
cities = ['London', 'New York', 'Sydney']
combined = list(zip(names, ages, cities))
print(combined)
# Output:
# [('Alice', 24, 'London'), ('Bob', 30, 'New York'), ('Charlie', 22, 'Sydney')]
zip(names, ages, cities) combines the three lists element-wise into tuples.
Depending on what you specify to be the result, that’s what you end up with. These examples show that we can either have a dictionary brought back, a list or even a tuple.
Quick Update: To get used to using these functions I built a task list to help use some of them so that I’m able to know how to use them. I used ChatGPT to help build an example task list and worked through them all and it gave me feedback on all of them too. I think it’s a good method to use and found it really insightful as the course materials didn’t really go over much on them. I found a new attribute inside the module itertools calls zip_longest which is where you can combine different lists with different lengths and have empty slots filled with a custom value like
"N/A".
Conclusion
Throughout this post, we’ve covered several advanced Python tools that will allow you to handle data more efficiently in your programs.
By understanding and using:
- Packing and Unpacking Arguments: We can pass data into functions flexibly and efficiently.
- Spreading Sequences: Splitting and joining sequences with ease.
- Enumerating Collections: Iterating over data while keeping track of the index.
- Zipping Iterables: Combining multiple lists into key-value pairs or tuples.
I hope this deep dive into these advanced techniques helps you feel more confident when writing Python code. They’re invaluable tools for solving problems quickly and writing clean, efficient code.
Most of this post was generated with using ChatGPT to see how well I am at making effective prompts. Tell me what you think. I did do my own rewording slightly using grammarly.
