I often used spread operator in TypeScript/JavaScript and I needed to do it in Python. The spread operator in TypeScript/JavaScript is ...
while it’s an asterisk *
in Python. Let’s check how it works.
Unpacking one dimensional List
Let’s start with a simple example. Prepending an asterisk to the variable that we want to unpack.
array1 = [1, 2, 3, 4]
array2 = [9, 8, 7, 6]
array_of_array = [array1, array2]
flatten_array = [*array1, *array2]
print(array_of_array) # [[1, 2, 3, 4], [9, 8, 7, 6]]
print(flatten_array) # [1, 2, 3, 4, 9, 8, 7, 6]
The items are correctly unpacked.
Unpacking two dimensional List
The asterisk unpacks only the first level. If the nested list needs to be flattened, we need another way.
print(*array_of_array) # [1, 2, 3, 4] [9, 8, 7, 6]
print(*flatten_array) # 1 2 3 4 9 8 7 6
flatten_array2 = [
*array_of_array[0],
*array_of_array[1],
]
print(flatten_array2) # [1, 2, 3, 4, 9, 8, 7, 6]
Add list to a list
If both two variables are list, we can use plus operator. If the original variable needs to be updated, extend
is also available.
print(array_of_array[0] + array_of_array[1]) # [1, 2, 3, 4, 9, 8, 7, 6]
array_of_array[0].extend(array_of_array[1])
print(array_of_array[0]) # [1, 2, 3, 4, 9, 8, 7, 6]
But beware of the fact that the referenced value is updated. The array_of_array
was created in the following way.
array1 = [1, 2, 3, 4]
array2 = [9, 8, 7, 6]
array_of_array = [array1, array2]
flatten_array = [*array1, *array2]
An asterisk is not used for it. It means that the reference of array1
is used there. If we access array_of_array[0]
, it accesses array1
. In other words, all operations for array_of_array[0]
affect the original variable array1
.
See the following result.
print(array1) # [1, 2, 3, 4, 9, 8, 7, 6]
print(flatten_array) # [1, 2, 3, 4, 9, 8, 7, 6]
print(flatten_array2) # [1, 2, 3, 4, 9, 8, 7, 6]
array1 is accidentally updated. flatten_array
and flatten_array2
are created by using an asterisk, they are not affected because the values are copied from the original variable. It’s not a reference.
Use asterisk to pass parameters to a function
A function might require parameters separately while we have a list of data. We can use an asterisk to pass the parameters in this case.
def calc_sum(a, b, c, d):
print(f"sum({a}, {b}, {c}, {d}):{a+b+c+d}")
calc_sum(*[1, 2, 3, 4]) # sum(1, 2, 3, 4):10
An error occurs if the list has more items than the required number of parameters. In this case, pass only the required number of parameters by using a colon for example.
params = [1, 2, 3, 4, 5]
# Too many positional arguments for function call
# calc_sum(*params)
calc_sum(*params[0:4]) # sum(1, 2, 3, 4):10
calc_sum(*params[1:5]) # sum(2, 3, 4, 5):14
calc_sum(*params[-4:]) # sum(2, 3, 4, 5):14
Check the following post too for the list with a colon if you want to know more about it.
Two asterisks are needed for Dictionary
If an asterisk is used for a dictionary, only keys are extracted. It’s similar to keys()
method.
data_dict = {
"one": 1,
"two": 2,
"three": 3,
}
print(*data_dict) # one two three
print(" ".join(data_dict.keys())) # one two three
If it’s assigned to a list, it can be used in the same way as keys()
but if it’s assigned with {}
, the data type will be set
.
array_from_dict = [*data_dict]
set_from_dict = {*data_dict}
print(array_from_dict) # ['one', 'two', 'three']
print(isinstance(set_from_dict, set)) # True
print(set_from_dict) # {'one', 'three', 'two'}
print(set_from_dict.pop()) # one
I guess we rarely implement it in this way to use keys. It’s better to use keys()
method in this case for readability.
To create a new dict from a dict, two asterisks are needed.
dict_from_dict = {**data_dict}
print(isinstance(dict_from_dict, dict)) # True
# {'one': 1, 'two': 2, 'three': 33, 'four': 4}
print({**dict_from_dict, "four": 4, "three": 33})
# {'four': 4, 'three': 3, 'one': 1, 'two': 2}
print({"four": 4, "three": 33, **data_dict})
As you can see, if the same key appears in the same dict, the last one is used.
Flatten a nested list
Do you need to flatten a nested list? Using an asterisk is not enough in this case.
nested_arrays = [[1, 2, 3], [4, 5], [6, [7, [8, 9]]]]
def flatten(array: List[Any]):
result = []
for item in array:
result.extend(item)
return result
print(flatten(nested_arrays)) # [1, 2, 3, 4, 5, 6, [7, [8, 9]]]
The nested list is not flattened. So, the internal item needs to be checked whether or not it’s a list.
def recursive_flatten(array: List[Any]):
result = []
for item in array:
if isinstance(item, list):
result.extend(recursive_flatten(item))
else:
result.append(item)
return result
print(recursive_flatten(nested_arrays)) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Check the following post if you search for another way to flatten a list.
Comments