python如何确定参数是引用还是值?

时间:2009-08-27 18:31:36

标签: python pointers reference

在C ++中,void somefunction(int)传递一个值,而void somefunction(int&)传递一个引用。在Java中,基元通过值传递,而对象通过引用传递。 python是如何做出这个决定的?

编辑:由于所有内容都是通过引用传递的,为什么会这样:

def foo(num):
    num *= 2

a = 4
foo(a)

print(a)

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

6 个答案:

答案 0 :(得分: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]

答案 1 :(得分: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中的引用最相似。

答案 2 :(得分:3)

响应您的编辑,这是因为整数在Python中是不可变的。所以a没有因为运行此代码时没有更改的原因而改变:

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

您没有更改num(因此a),您正在创建一个新号码并将其分配给num。

答案 3 :(得分:3)

参数实际上是按值传递的。函数传递给变量引用的对象,而不是变量本身。函数不能重新绑定调用者的变量。函数不能更改不可变对象,但可以更改(请求更改)可变对象。

答案 4 :(得分:1)

一切都通过引用传递。一切都是一个对象。

答案 5 :(得分:1)

这不是关于函数调用语义,而是赋值语义。在Python中,通过重新绑定引用来完成赋值,而不是通过覆盖原始对象。这就是为什么示例代码打印4而不是8 - 它与对象的可变性无关,更多的是* =运算符不是mutator而是乘法后跟赋值。这里 num * = 2 实质上是将该函数中的“ num ”名称重新绑定到值为“ num * 2 ”的新对象。您传入的原始值在整个过程中保持不变。