I was trying to set the default value of an argument with a standard dictionary that is built with another function. However, when calling the function which requires said argument a second time, the information from the previous run is leaking into the second run.
standard_list = ['a','b','c','d']
my_list = ['b','d']
my_second_list = ['a','b']
def init_dict():
my_dict = {}
for key in standard_list:
my_dict[key]=0
return my_dict
def create_shopping_dict(shopping_list, standard_dict=init_dict()):
for key in shopping_list:
standard_dict[key]=1
return standard_dict
my_shopping_list = create_shopping_dict(my_list)
my_second_shopping_list = create_shopping_dict(my_second_list)
print(my_second_shopping_list)
Expected:
{'a': 1, 'b': 1, 'c': 0, 'd': 0}
Actual:
{'a': 1, 'b': 1, 'c': 0, 'd': 1}
Moving the initialization of the standard_dict argument inside the function solves the problem, but I don't understand why.
def create_shopping_dict(shopping_list):
standard_dict=init_dict()
for key in shopping_list:
standard_dict[key]=1
return standard_dict
If it was the case that Python stored the argument value for further runs instead of using the default value, then the following code would print 1 then 2, but it prints 1 and 1.
def test(a=0):
a =1
return a
print(test())
print(test())
CodePudding user response:
That's because the function to get default value is executed only once, and same reference is kept for later i.e. the function doesn't get called twice. You can define the parameter to be None
as default, and inside the function check for default then call the function to initilize the value, it should work fine:
def create_shopping_dict(shopping_list, standard_dict=None):
if standard_dict is None:
standard_dict = init_dict() # Same as your 2nd case
for key in shopping_list:
standard_dict[key]=1
return standard_dict
To prove above hypothesis, you can either add print
statement inside your initializer function and see if it gets called. Or, you can just check the id of the standard_dict
argument inside the create_shopping_dict
function:
def init_dict():
print("Function called")
my_dict = {}
for key in standard_list:
my_dict[key]=0
return my_dict
def create_shopping_dict(shopping_list, standard_dict=init_dict()):
print("###ID: ", id(standard_dict))
for key in shopping_list:
standard_dict[key]=1
return standard_dict
my_shopping_list = create_shopping_dict(my_list)
my_second_shopping_list = create_shopping_dict(my_second_list)
# Console output:
Function called
###ID: 2113624480328
###ID: 2113624480328
{'a': 1, 'b': 1, 'c': 0, 'd': 1}
As you can see, the initializer is called only once, and the id
of standard_dict
for both the calls to create_shopping_dict
are identical.