I know that Python’s default parameters are only evaluated when the function is created, but I’m confused in my example why my first default parameter is getting reset each time but my empty set isn’t.
In the below, I am calling the main_func()
from somewhere else with a list of dates. Then iterating through the dates to collect a bunch of data from some api. I need to get at least 100 unique pieces of data for each date, so I repeat the __get_data_for_date
function for each date until their are 100 responses. When I then go onto the next date, the start_index
gets reset to 0, but my unique_data
set keeps the data from before.
Why does start_index
get reset but not unique_data
?
# when called from main_func, start_index is always reset but unique_data always keeps its data from the previous calls def __get_data_for_date(date, start_index=0, unique_data=set()): data = api_call(date) data_set = unique_data for d in data: data_set.add(d['id']) if len(unique_data) < 100: return __get_data_for_date(date, start_index=start_index+len(data), unique_data=data_set) return data_set def main_func(dates): final_data = [] for date in dates: # start_index is back to 0 but unique_data still has the previous data data = __get_data_for_date(date) final_data.append(data) return final_data
Advertisement
Answer
start_index
is never reset. It was never changed in the first place.
start_index
is a number, which is immutable. Since it’s immutable, it can never change.
Compare that to a set, which is mutable, and can change. When you do data_set.add(d['id'])
, you are directly mutating (altering) the object that is stored as the default argument.
So, in both cases, the object that is stored as the default argument never changes (you can verify that by checking the id
of each). The difference is that the immutable number is never itself altered, while the mutable set is.
Although, to be clear, the problem isn’t that the set is mutable. The problem is that it’s mutated. It’s safe to have a mutable default argument if you never mutate it (assuming you don’t forget that it’s a default argument in the future).