我来自C ++背景,所以这个问题对我来说似乎有点荒谬: 我们假设我有一个功能:
def scale(data, factor):
for val in data:
val *= factor
这不按预期工作,如果我传递一个列表,它什么都没改变,但是
def scale(data, factor):
for index, val in enumerate(data):
data[index] *= factor
和lst = [val * factor for val in lst]
正常运行。
Python如何处理参数传递?我怎么知道实际的引用或别名是否通过了?
答案 0 :(得分:4)
如果要改变列表,则需要引用元素。此版本使用map
(可以使用列表推导编写)
def scale(data, factor):
return map(lambda x : x*factor, data)
lambda函数是anonymous
函数。
>>> (lambda x : x + 1) (5)
6
在这种情况下,x
取代了变量5 + 1
因此,在这种情况下,我们遍历将函数f(x) -> x * factor
应用于列表的每个元素的列表。原始列表没有变异,而是我们返回一个新版本。
答案 1 :(得分:3)
在python中,基本数据类型按值传递 - 例如int
,str
,bool
等按值传递
classes
,enum
,list
,dict
等派生数据类型通过引用传递。
在您的示例中,问题是您如何使用for循环 - 而不是函数参数。如果你这样做:
for val in lst:
val += 1
lst内的值不会更新,因为val
与lst[0]
,lst[1]
不同,依此类推val
是基本的数据类型。因此,即使在这里,val
也会按值复制。
其次,在enumerate
的示例中:
但是,当您遍历enumerated
列表时,您正在使用data[index]
- 它会修改实际列表中的元素。
最后,在您使用生成器的示例中:
lst = [val * factor for val in lst]
- 此处生成器遍历每个元素并创建一个新列表,该列表再次存储在lst
中。这类似a = a + 2
,但扩展到列表。
答案 2 :(得分:1)
这种行为是因为基本数据类型是按值传递的,而像列表这样的派生数据类型是通过引用传递的,请考虑这个
>>> x = 24
>>> x + 1
25
>>> x
24
但另一方面有一个列表
>>> y = [1, 2, 3, 4]
>>> y.remove(2)
>>> y
[1,3,4]
因此,在基本数据类型的情况下,在对它们执行操作时应始终小心重新分配值,并且还要小心通过引用传递的数据类型,因为您可能在不知道的情况下意外修改变量