在C ++中,void somefunction(int)
传递一个值,而void somefunction(int&)
传递一个引用。在Java中,基元通过值传递,而对象通过引用传递。 python是如何做出这个决定的?
编辑:由于所有内容都是通过引用传递的,为什么会这样:
def foo(num):
num *= 2
a = 4
foo(a)
print(a)
打印'4'而不是'8'?
答案 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 ”的新对象。您传入的原始值在整个过程中保持不变。