英文:
Why my local variable in a function affect global variable without using 'global'?
问题
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.copy()
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 current # Return the original resources if there's not enough
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)
输出应该如下所示:
{'water': 300, 'milk': 200, 'coffee': 100}
{'water': 50, 'milk': 100, 'coffee': 76}
你的问题是因为在 calculate
函数中,你直接修改了 remaining
,它指向了全局变量 resources
的引用,因此导致了全局变量的值也被修改了。为了避免这种情况,你可以在 calculate
函数内部创建一个新的副本,然后在副本上进行修改,而不是直接修改全局变量。这样,全局变量的值就不会被改变。
英文:
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?
答案1
得分: 1
resources
是一个可变对象。当它被传递给 calculate
时,current
成为该对象的另一个名称。
remaining = current
将为该对象分配另一个名称,并且 remaining[i] = remaining[i] - ingredients[i]
会对该对象进行变异。
要修复,使用:
remaining = current.copy()
这将创建一个新对象,对其进行修改不会影响原始对象。
请注意,如果原始对象本身包含可变对象,则可能需要使用 copy.deepcopy()
,但在这种情况下不需要。
英文:
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.
答案2
得分: 0
你正在更改resources
的值,因为它是一个可变对象。
这是初始声明的值:
resources = {
"water": 300,
"milk": 200,
"coffee": 100,
}
然后,您调用一个函数来计算(我用RESOURCES替换了current以帮助可视化),然后只是说remaining = RESOURCES
,通过说remaining = current
来实现。参数可以命名为任何名称,您传递的是值。在这种情况下,这是一个可变(可更改)对象。
remaining = calculate(resources, ingredients)
def calculate(RESOURCES, ingredients):
remaining = RESOURCES
一旦您理解了这一点,很容易看出以下代码更改了resources
的值,您将remaining
分配为传入的可变字典,因此通过更改它的值,您更改了它所代表的对象的值。
for i in ingredients:
remaining[i] = remaining[i] - ingredients[i]
如果这不清楚,还有另一种思考方式:
x = [1, 2, 3]
y = x
x = ['a', 'b']
如果我`print(y)`,值将为`[1, 2, 3]`,但是如果我执行`x[0] = 2`,那么`print(y)`的输出将变为`[2, 2, 3]`,因为我更改了可变对象`x`的**值**。
听起来您想传递一个`resources`的副本,所以尝试使用`dict2 = dict(dict1)`。这也是类和工厂设计模式可能对您有用的一个很好的示例。
<details>
<summary>英文:</summary>
You're changing the value of `resources` as it's a mutable object.
Here's the initial declared value:
resources = {
"water": 300,
"milk": 200,
"coffee": 100,
}
You then make a function call to calculate which (i've replaced current with RESOURCES to help visualize) you then just say `remaining = RESOURCES` by saying `remaining = current`. The argument could be named anything, what you pass in is the value. In this case that is a mutable (changeable) object.
remaining = calculate(resources, ingredients)
def calculate(RESOURCES, ingredients):
remaining = RESOURCES
Once you understand that, it's easy to see why the following changes the value of `resources`, you assigned remaining to be the mutable dictionary you passed in, so by changing it's values you change the value of the object it represents.
for i in ingredients :
remaining[i] = remaining[i] - ingredients[i]
Here's another way to think about it if that doesn't click:
x = [1, 2, 3]
y = x
x = ['a', 'b']
if I `print(y)`, the value will be `[1, 2, 3]`, however if I did `x[0] = 2` my output for `print(y)` would then become `[2, 2, 3]` as I've changed the **value** of my mutable object `x`.
It sounds like you want to pass in a copy of resources, so try using `dict2 = dict(dict1)`. This is also a great example of how a class and the factory design pattern may be of use to you.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论