Python 函数调用对全局变量有副作用
我正在研究课程中的背包问题: 它具有以下输入:Python 函数调用对全局变量有副作用,python,Python,我正在研究课程中的背包问题: 它具有以下输入: cows = {"Jesse": 6, "Maybel": 3, "Callie": 2, "Maggie": 5} 我必须返回一个列表作为输出,如下所示: [['Jesse', 'Maybel'], ['Callie', 'Maggie']] 我编写的函数似乎运行良好,因为它返回正确的结果: def greedy_cow_transport(cows,capacity): ocupied = 0 current_trip =
cows = {"Jesse": 6, "Maybel": 3, "Callie": 2, "Maggie": 5}
我必须返回一个列表作为输出,如下所示:
[['Jesse', 'Maybel'], ['Callie', 'Maggie']]
我编写的函数似乎运行良好,因为它返回正确的结果:
def greedy_cow_transport(cows,capacity):
ocupied = 0
current_trip = []
all_trips = []
while(True):
for cow in cows:
if ocupied+cow[1] < capacity:
current_trip.append((cow[0]))
ocupied += cow[1]
cows.remove(cow)
else:
all_trips.append(current_trip)
ocupied = 0
current_trip = []
if len(cows)==0:
all_trips.append(current_trip)
break
return all_trips
变量顺序是一个空列表。
我不明白为什么会发生这种情况,因为我只在函数范围内使用.remove方法。为什么这些会影响我的主要变量 考虑这个例子:
def modify(arr):
arr.remove(4)
numbers = [1, 2, 3, 7, 3, 4]
modify(numbers)
print(numbers) # prints [1, 2, 3, 7, 3] (modified)
您可能期望将参数传递给函数的行为类似于整数:
def modify(i):
i = 6
j = 7
modify(j)
print(j) # prints 7 (not modified)
您可能认为Python总是复制参数以在函数中使用,但事实并非如此。执行i=6
操作时,您正在设置i
的变量名,以引用值为6
整数的新对象。因此,不会修改全局i
但是,当您使用list.remove(x)
时,您正在修改作为参数传递的实际对象。namelist
的变量仍然引用原始对象
诚然,这一解释可能相当令人困惑。添加一些id()
将有助于澄清问题
def modify(arr):
print(id(arr))
arr.remove(4)
print(id(arr)) # they print the same thing
numbers = [1, 2, 3, 7, 3, 4]
modify(numbers)
print(numbers) # prints [1, 2, 3, 7, 3] (modified)
现在使用整数:
def modify(i):
print(id(i))
i = 6
print(id(i)) # nope, different ids!
j = 7
modify(j)
print(j) # prints 7 (not modified)
考虑这个例子:
def modify(arr):
arr.remove(4)
numbers = [1, 2, 3, 7, 3, 4]
modify(numbers)
print(numbers) # prints [1, 2, 3, 7, 3] (modified)
您可能期望将参数传递给函数的行为类似于整数:
def modify(i):
i = 6
j = 7
modify(j)
print(j) # prints 7 (not modified)
您可能认为Python总是复制参数以在函数中使用,但事实并非如此。执行i=6
操作时,您正在设置i
的变量名,以引用值为6
整数的新对象。因此,不会修改全局i
但是,当您使用list.remove(x)
时,您正在修改作为参数传递的实际对象。namelist
的变量仍然引用原始对象
诚然,这一解释可能相当令人困惑。添加一些id()
将有助于澄清问题
def modify(arr):
print(id(arr))
arr.remove(4)
print(id(arr)) # they print the same thing
numbers = [1, 2, 3, 7, 3, 4]
modify(numbers)
print(numbers) # prints [1, 2, 3, 7, 3] (modified)
现在使用整数:
def modify(i):
print(id(i))
i = 6
print(id(i)) # nope, different ids!
j = 7
modify(j)
print(j) # prints 7 (not modified)
由于您试图使用
copy.copy
,我假设您理解python通过参数的值传递对对象的引用。您只需要保留对排序顺序的引用
剧本
$ cat cows.py
...
order = sorted(cows.items(), key=lambda x: x[1], reverse= True)
order_copy = copy.copy(order)
print(order)
print(greedy_cow_transport(order_copy,capacity))
print(order)
输出
$ python3 cows.py
[('Jesse', 6), ('Maggie', 5), ('Maybel', 3), ('Callie', 2)]
[['Jesse'], ['Callie', 'Maggie'], ['Maybel']]
[('Jesse', 6), ('Maggie', 5), ('Maybel', 3), ('Callie', 2)]
请注意,如果您有嵌套列表,则需要
deepcopy
,因为您尝试使用copy.copy
,我假设您理解python通过参数的值传递对对象的引用。您只需要保留对排序顺序的引用
剧本
$ cat cows.py
...
order = sorted(cows.items(), key=lambda x: x[1], reverse= True)
order_copy = copy.copy(order)
print(order)
print(greedy_cow_transport(order_copy,capacity))
print(order)
输出
$ python3 cows.py
[('Jesse', 6), ('Maggie', 5), ('Maybel', 3), ('Callie', 2)]
[['Jesse'], ['Callie', 'Maggie'], ['Maybel']]
[('Jesse', 6), ('Maggie', 5), ('Maybel', 3), ('Callie', 2)]
请注意,如果您有嵌套列表,则需要
deepcopy
您有两个变量引用同一列表,而不是两个列表。此处的范围无关。作用域仅定义哪些名称解析为哪些对象,而不限制mutator方法影响对象的位置。例如,您可以在局部范围中有一个名称,该名称引用的对象在全局范围中也有一个引用。基本上,您需要一个deepcopy,而不是在函数中复制cows
,将其称为remainingcows
。此外,您正在对要从中删除的容器进行迭代,这通常不会很好地结束。您有两个变量引用同一个列表,而不是两个列表。这里的范围无关。作用域仅定义哪些名称解析为哪些对象,而不限制mutator方法影响对象的位置。例如,您可以在局部范围中有一个名称,该名称引用的对象在全局范围中也有一个引用。基本上,您需要一个deepcopy,而不是在函数中复制cows
,将其称为remainingcows
。此外,您正在迭代要从中移除的容器,这通常不会很好地结束。