I am still learning about python. I am stuck with this local variable behavior. I am trying to make a simple coffee machine. this is the part of code.
MENU = {
"espresso": {
"ingredients": {
"water": 50,
"coffee": 18,
},
"cost": 1.5,
},
"latte": {
"ingredients": {
"water": 200,
"milk": 150,
"coffee": 24,
},
"cost": 2.5,
},
"cappuccino": {
"ingredients": {
"water": 250,
"milk": 100,
"coffee": 24,
},
"cost": 3.0,
}
}
resources = {
"water": 300,
"milk": 200,
"coffee": 100,
}
def calculate(current, ingredients):
remaining = current
print(remaining)
print(ingredients)
for i in ingredients :
remaining[i] = remaining[i] - ingredients[i]
if remaining[i] < 0 :
print(f"sorry, there is not enough {i}")
print(remaining)
return resources
return remaining
user_input = input("What would you like? (espresso/latte/cappuccino): ").lower()
coffee = MENU[user_input]
ingredients = coffee["ingredients"]
cost = coffee["cost"]
# check if coffee can be made.
remaining = calculate(resources, ingredients)
print(resources)
print(remaining)
When I run it, I expect that the global variable of resources won't change. If I choose latte, the output should be like this:
{'water': 300, 'milk': 200, 'coffee': 100}
{'water': 50, 'milk': 100, 'coffee': 76}
However, the printed resources change its value. I noticed using thonny debugger that when the calculation occurs, both local and global change their value. I didn't use global command. Can anyone explain why?
resources
is a mutable object. When it is passed to calculate
, current
becomes another name for that object.
remaining = current
assigns another name to the object, and remaining[i] = remaining[i] - ingredients[i]
mutates that object.
To fix, use:
remaining = current.copy()
This will make a new object that modifying won’t affect the original.
Note that if the original object itself contains mutable objects, then copy.deepcopy()
may be needed, but not in this case.