#swe #flashcards

Related: Software engineering | 8-14-2025 Tuples | 8-15-2025 Dictionaries

Concept: Essential Python technique for handling multiple values, function arguments, and data structures.


Unpacking

Unpacking refers to the act of extracting data from a structured format such as a tuple, list, or dictionary into individual variables.

Multiple assignment

Unpacked values an be assigned to variables within the same statement, this is common referred to as multiple assignment. In multiple assignment, the number of variables on the left-hand side of the assignment operator must match the number of elements in the iterable on the right-hand side.

a,b = 1,2
print(a)

c,d,f = 1, "Hello",True
print(c)
print(d)
print(f)

If the multiple assignment gets an incorrect number of values, it will throw a ValueError

x,y,x = 1,2

Multiple assignment can be used to swap elements in lists. This practice is pretty common in sorting algorithms. You can’t swap elements in tuples

num = [1,2]
num[0],num[1] = num[1],num[0]
print(num)

In python it is possible to unpack the elements of lists/tuple/dictionary into distinct variables. Since values appear within lists/tuples in a specific order they are unpacked into variables in the same order.

fruits = ("apple","banana", "cherry")
x,y,z = fruits
print(x)

If there are values that are not needed then you can use _ to flag them:

fruits = ["apple", "banana", "cherry"]
_,_,z = fruits
print(_)
print(z)

Deep unpacking

Unpacking and assigning values nested list/tuple works in the same way as unpacking but often needs qualifiers to clarify the position or context:

fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
[[a, b], [c, d]] = fruits_vegetables
print(a,d)

fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
[a, [c, d]] = fruits_vegetables
print(a)
print(c)

If the unpacking has variables with incorrect placement and/or an incorrect number of values, you will get a ValueError:

fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
[[a, b], [d]] = fruits_vegetables

Unpacking a list/tuple with *

When unpacking a list/tuple you can use the * operator to capture the leftover values. The starred variable will be assigned a list containing all items after the first two, even if it's just one item or none.

fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
x, *last = fruits # extract the first element and then the remaining values can be placed into a new list
print(x)
print(last)

x, *middle, y= fruits # extract the values at the beginning and end of the `list` while grouping all the values in the middle:
print(x)
print(y)
print(middle)

fruits_vegetables = [["apple", "banana", "melon"], ["carrot", "potato", "tomato"]]
[[a, *rest], b] = fruits_vegetables # you can also use * in deep unpacking
print(a)
print(rest)
print(b)

Unpacking a dictionary

Unpacking a dictionary is a bit different from unpacking a list/tuple. When you unpack a dictionary, you are unpacking the keys of the dictionary, not the values.

fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
x, y, z = fruits_inventory
print(x)
a,b,c = fruits_inventory.values()
print(a)

e,f,g = fruits_inventory.items()
print(e)

Packing

Packing is the ability to group multiple values into one list that is assigned to a variable. This is useful for returning multiple values from a function or for creating a list of values that can be passed to another function. It also makes it possible to perform merges on 2 or more lists / tuples / dicts.

Packing a list/tuple with *

fruits = ("apple", "banana", "cherry")
more_fruits = ["orange", "kiwi", "melon", "mango"]

combined_fruits_tuple = *fruits, *more_fruits # If there is no * on to the left of the "=" the result is a tuple
print("Fruits tuple: ",combined_fruits_tuple)

*combined_fruits_list, = *fruits, *more_fruits # If the * operator is used on the left side of "=" the result is a list. Note the trailing comma.
print("Fruits list: ",combined_fruits_list)

Packing a dictionary with *

Packing a dictionary is done by using the ** operator. This will pack all key-value pairs from one dictionary into another dictionary, or combine two dictionaries together.

fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
more_fruits_inventory = {"orange": 4, "kiwi": 1, "melon": 2, "mango": 3}

combined_fruits_inventory = {**fruits_inventory, **more_fruits_inventory}# fruits_inventory and more_fruits_inventory are unpacked into key-values pairs and combined.
print(combined_fruits_inventory)

Usage of * and ** with functions

When you create a function that accepts an arbitrary number of arguments, you can use *args or **kwargs in the function definition. *args is used to pack an arbitrary number of positional (non-keyword) arguments as a tuple and **kwargs is used to pack an arbitrary number of keyword arguments as a dictionary.

def my_function(*args):# This function is defined to take any number of positional arguments
	print(args)
my_function(1,2,3)
my_function("Hello")
my_function(1, 2, 3, "Hello", "Mars")

def my_function2(**kwargs):# This function is defined to take any number of keyword arguments
	print(kwargs)
	
my_function2(a=1, b=2, c=3)
my_function2(d= ('a','b','c'),e = ('d','e','f'),f = "mars")

Using *args and **kwargs together

*args and **kwargs can also be used in combination with one another:

def my_function(*args, **kwargs):
	print(sum(args))
	for key, value in kwargs.items():
		print(str(key) + " = " + str(value))
		
my_function(1, 2, 3, a=1, b=2, c=3)

You can also structure your arguments like this: def my_function(<positional_args>, *args, <key-word_args>, **kwargs)

def my_function(a,b, *args):
	print(a)
	print(b)
	print(args)
	
my_function(1, 2, 3, 4, 5)

Unpacking into function calls

You can use * to unpack a list / tuple of arguments into a function call. This is very useful for functions that don't accept an iterable:

def my_function(a,b,c):
	print(c)
	print(b)
	print(a)
numbers = [1,2,3]
my_function(*numbers)

The zip() Function

The zip() function takes those individual lists and groups their elements together into tuples. It pairs the first item of each list, then the second item of each list, and so on.

print(zip(['x', 'y', 'z'], [1, 2, 3], [True, False, True]))

Using * unpacking with zip()

A common use case is using zip to take multiple iterables and returns a list of tuples with the values from each iterable grouped.

values = (["x","y","z"],[1, 2, 3], [True, False, True])
a, *rest = zip(*values)
print(rest)
print(a)

Functions which helps the locomotive engineer to keep track of the train.

def get_list_of_wagons(*wagons): # takes the input and stores them in a tuple(wagons)
    return list(wagons)
def fix_list_of_wagons(each_wagons_id, missing_wagons):
    x,y,z, *remainder = each_wagons_id # extracts the first 3 elements from each_wagon_id
    
    *wagon_list, = z,*missing_wagons,*remainder,x,y # arranges all the extracted elements
    return wagon_list
def add_missing_stops(trip, **stops1):
    a = stops1.values() # returns dict_values view 
    trip = {**trip, 'stops' : list(a) } # kwargs iterates over the trip dict and returns it list(a) turns our view to a list and adds it as the stops value
    return trip
def extend_route_information(route, more_route_information):
    extend_route_information = {**route, **more_route_information} # unpack both dicts and pack them into the new dict
    return extend_route_information
def fix_wagon_depot(wagons_rows):
    return [list(i) for i in zip(*wagons_rows)] #turns every tuple in zip into a list and returns it  fix just the indentation issue chnage nothing else