在Python中可以不使用指针而传递引用作为参数吗?

6 投票
2 回答
11572 浏览
提问于 2025-04-17 23:17

因为Python没有指针,我在想怎么才能把一个对象的引用传递给一个函数,而不是复制整个对象。这个例子有点牵强,但假设我写了一个这样的函数:

def some_function(x):
    c = x/2 + 47
    return c

y = 4
z = 12

print some_function(y)
print some_function(z)

根据我的理解,当我调用some_function(y)时,Python会分配新的空间来存储这个参数的值,然后在函数返回c后就会删除这些数据,因为这些数据不再需要。既然我在some_function里面并没有改变这个参数,那我怎么才能在函数内部简单地引用y,而不是在传递时复制y呢?在这种情况下影响不大,但如果y非常大(比如一个巨大的矩阵),复制它可能会消耗大量的时间和空间。

2 个回答

2

在Python中,参数总是以“引用”的方式传递。

Python中的参数工作方式以及文档中对它们的解释,可能会让刚接触这门语言的人感到困惑,尤其是如果你之前学过其他语言,那些语言允许你选择“值传递”和“引用传递”。

在Python中,“引用”其实就是一个指针,带有一些额外的信息,帮助垃圾回收器完成工作。而每个变量和每个参数始终都是“引用”。

所以,Python内部实际上是将一个“指针”传递给每个参数。你可以通过这个例子轻松看出这一点:

>>> def f(L):
...     L.append(3)
... 
>>> X = []
>>> f(X)
>>> X
[3]

变量X指向一个列表,而参数L是这个列表“指针”的一个副本,而不是列表本身的副本。

需要注意的是,这和C++中的“引用传递”(使用&修饰符)或Pascal中的var修饰符并不相同。

16

很遗憾,你的理解完全错误。Python 并不是在复制值,也不是为新值分配空间。它传递的是一个值,这个值实际上是指向对象的引用。如果你修改了这个对象(而不是重新绑定它的名字),那么原来的对象也会被修改。

编辑

我希望你不要再担心内存分配的问题:Python 不是 C++,大多数时候你根本不需要考虑内存。

用列表来演示重新绑定会更简单:

def my_func(foo):
    foo.append(3)  # now the source list also has the number 3
    foo = [3]      # we've re-bound 'foo' to something else, severing the relationship
    foo.append(4)  # the source list is unaffected
    return foo


original = [1, 2]
new = my_func(original)

print original     # [1, 2, 3]
print new          # [3, 4]

如果你把思考方式转变为关注名字而不是变量,可能会更有帮助:在函数内部,名字 "foo" 一开始是指向原始列表的引用,但后来我们把这个名字改成指向一个新的、不同的列表。

撰写回答