77

当您将列表、数组之类的集合传递给 python 中的另一个函数时,它会复制它,还是只是一个指针?

4

8 回答 8

93

Python通过 value 传递对对象的引用

Python 按值传递对对象的引用(如 Java),Python 中的一切都是对象。这听起来很简单,但随后您会注意到某些数据类型似乎表现出按值传递的特征,而另一些数据类型似乎表现得像按引用传递......这是怎么回事?

了解可变和不可变对象很重要。一些对象,如字符串、元组和数字,是不可变的。在函数/方法内部更改它们将创建一个新实例,而函数/方法外部的原始实例不会更改。其他对象,如列表和字典是可变的,这意味着您可以就地更改对象。因此,更改函数/方法内部的对象也会更改外部的原始对象。

于 2009-02-10T21:53:45.703 回答
78

问题是,整个参考/价值概念不适合 python。Python 没有变量的“值”。Python 只有对象和引用对象的名称。

因此,当您调用一个函数并在括号内放置一个“名称”时,如下所示:

def func(x): # defines a function that takes an argument
    ... # do something here

func(myname) # calling the function

myname传递的是指向的实际对象,而不是名称 myname 本身。在函数内部,另一个名称( x) 用于引用传递的同一对象。

如果它是可变的,您可以修改函数内部的对象,但您不能更改外部名称指向的内容。和你做的时候一样

anothername = myname

因此,我可以回答您的问题:

它是“按值传递”,但所有值都只是对对象的引用。

于 2009-02-10T22:29:25.697 回答
26

这里的答案很有帮助,但我发现需要展示我没有看到的这种细微差别,我已经通过随后的 CL 实验向自己证明了这一点:

  1. 在函数调用中不能单独更改不可变对象。(到目前为止的答案已经说了很多......)
  2. 但是,包含在可变对象中的不可变对象可以在方法调用中重新分配。

'num' 在这里没有改变,因为它是一个不可变的 Number 对象[支持我的观点 1。]:

def incr_num(num):
    num += 1

num = 0

num
0

incr_num(num)

num
0

'list[0]' 这里也是一个不可变的 Number 对象。

def incr_list(list):
    list[0] += 1

list = [0]

list[0]
0

incr_list(list)

list[0]
1

那么,作为不可变的 Number 对象,'list[0]' 是如何改变的(支持我的观点 2.),而上面示例的 Number 对象 'num' 没有? 不可变的 Number 对象“list[0]”包含在可变列表对象“list”中,而第一个示例中的“num”只是一个非包含的 Number 对象(不可变)。

虽然出于善意,但我觉得@Stephen Pape评价最高的答案(引用如下)和其他一些类似的答案并不完全正确(这促使我写下这个答案):

一些对象,如字符串、元组和数字,是不可变的。在函数/方法内部更改它们将创建一个新实例,而函数/方法外部的原始实例不会更改。

我上面的第二个代码实验显示了一个 Number 对象 ('list[0]') 在方法内被更改,然后函数外部的原始实例发生了更改。

于 2012-11-27T06:08:04.897 回答
7

传递了引用,但如果参数是不可变对象,则在方法中对其进行修改将创建一个新实例。

于 2009-02-10T21:54:50.537 回答
4

对象被传递。不是副本,而是对底层对象的引用。

于 2009-02-10T21:53:42.723 回答
3

我还建议查看copy模块:

用于复制的 Python 文档

它将帮助您了解潜在问题以及如何使用它来执行您自己的深度复制。

于 2009-02-10T21:58:57.097 回答
2

引用:

>>> x = [0,1,2,3]
>>> def foo(x_list):
    x_list[0] = 1


>>> foo(x)
>>> x
[1, 1, 2, 3]
于 2009-02-10T21:55:22.050 回答
1

请让我举一个谦虚的例子

def swap(a, b):
    x = a
    print id(x)
    print id(a)
    print id(b)
    a = b

    print id(a)
    b = x
    print id(b)
    a[0]= '20'




var1 = ['1','2','3','4']
var2 = ['5','6','7','8','9']
print id(var1)
print id(var2)

swap(var1, var2)

print id(var1)
print id(var2)
print var1
print var2

产生以下结果

28329344 var1 28331264 var2 28329344 x 28329344 a 28331264 b 后 a = b 28331264 a 后 b = x 28329344 b 后返回 28329344 var1 28331264 var2 ['1', '2', '3', ''] '6'、'7'、'8'、'9']

映射到内存地址 28329344 28331264 var1 var2 ab x 之后 a=b a 之后 b=x b 之后 a[0] = '20' [0] = '20' 之后 return ['1','2','3', '4'] ['20', '6', '7', '8', '9']

于 2012-10-22T10:26:54.440 回答