Python如何判断参数是引用还是值?

4 投票
6 回答
5258 浏览
提问于 2025-04-15 13:55

在C++中,void somefunction(int)是把一个值传递给函数,而void somefunction(int&)是把一个引用传递给函数。简单来说,前者是把数字的副本给函数,后者是把数字的地址给函数,让函数可以直接修改原来的数字。在Java中,基本数据类型(像数字和字符)是按值传递的,而对象则是按引用传递的。那Python是怎么决定的呢?

补充一下:既然所有东西都是按引用传递的,为什么这段代码:

def foo(num):
    num *= 2

a = 4
foo(a)

print(a)

打印的是'4'而不是'8'呢?

6 个回答

3

针对你的修改,原因是Python中的整数是不可变的。也就是说,a没有变化,跟你运行下面这段代码时a没有变化是同样的道理:

a = 4
num = a
num *= 2
print(a)

你并没有直接改变num(因此也没有改变a),而是创建了一个新的数字,然后把它赋值给了num

11

它通过引用来传递所有东西。即使你指定了一个数字值,它实际上是指向一个包含这个值的表。这就是静态语言和动态语言之间的区别。类型是和值绑定在一起的,而不是和容器绑定,变量只是指向一个“值空间”的引用,这个空间里存放着所有的值。你可以想象这个值空间里有所有可能的不可变对象(比如整数、浮点数、字符串),还有你自己创建的所有可变对象(比如列表、字典、对象)。当然,只有在你使用它们的时候,这些对象的存在才会变得具体化(也就是说,如果你在程序中从来没有用到数字42,那么在“值空间”里就不会为42分配任何空间)。

之所以这样,是因为它所指向的数字是一个不可变对象。4就是4,无论如何都不会改变。

def foo(num): # here, num is referring to the immutable entity 4
    num *= 2  # num now refers to the immutable entity 8

a = 4        # a now is pointing to the immutable entity 4
foo(a)       # a is still referring to the same entity 4

print(a)     # prints what a refers to, still 4

但是,如果你这样做

def foo(l):      # here, l refers to the list it receives
    l.append(5)  # the list is appended with the number 5

a = []       # a now is pointing to a specific mutable list 
foo(a)       # a is still referring to the same specific mutable list

print(a)     # prints what a refers to, the specific mutable list which now contains [5]
9

这里的术语有点争议。在Java社区,他们认为所有东西都是按值传递的:基本数据类型是按值传递的;引用也是按值传递的。(如果你不相信,可以在这个网站上搜索Java和按引用传递。)需要注意的是,在这个语言中,“对象”并不是值;只有指向对象的引用才算是值。

他们的区分在于,在Java中,当你传递一个引用时,调用者的原始引用变量是不能被被调用者改变的(也就是说,不能让它指向一个不同的对象),而这在按引用传递中是可以的。只有引用所指向的对象可以被修改,但这并不重要。

Python中的值和Java中的引用工作方式完全一样。如果我们用同样的定义,那么我们可以说Python中的一切都是引用,所有东西都是按值传递的。当然,Python社区中的一些人使用了不同的定义。

术语上的争议是大多数混淆的来源。

既然你提到了C++,那么你在Python中的代码在C++中大致相当于这样的代码:

void foo(const int *num) {
    num = new int(*num * 2);
}

const int *a = new int(4);
foo(a);

print(a);

注意,参数是一个指针,这和Java和Python中的引用最为相似。

撰写回答