参数是通过引用传递还是通过值传递?如何通过引用传递,以便下面的代码输出“Changed”而不是“Original”?

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change(self.variable)
        print(self.variable)

    def change(self, var):
        var = 'Changed'

另请参阅:为什么函数可以修改调用者感知的某些参数,而不能修改其他参数?


当前回答

由于似乎没有任何地方提到过模拟引用的方法,例如C++就是使用一个“update”函数并传递它而不是实际变量(或者更确切地说,“name”):

def need_to_modify(update):
    update(42) # set new value 42
    # other code

def call_it():
    value = 21
    def update_value(new_value):
        nonlocal value
        value = new_value
    need_to_modify(update_value)
    print(value) # prints 42

这对于“仅输出引用”或具有多个线程/进程的情况(通过使更新函数线程/多处理安全)非常有用。

显然,上面不允许读取值,只允许更新它。

其他回答

或者,你可以使用看起来像这样的ctypes

import ctypes

def f(a):
    a.value=2398 ## resign the value in a function

a = ctypes.c_int(0)
print("pre f", a)
f(a)
print("post f", a)

因为a是一个c整数,而不是python整数,并且通过引用传递。然而,你必须小心,因为可能会发生奇怪的事情,因此不建议

Python的传递赋值方案与C++的引用参数选项并不完全相同,但实际上它与C语言(以及其他语言)的参数传递模型非常相似:

不可变的参数实际上是“按值”传递的。整数和字符串等对象是通过对象引用传递的,而不是通过复制传递的,但因为无论如何都不能在原地更改不可变的对象,所以效果很像复制。可变参数是“通过指针”有效传递的字典也通过对象引用传递,这与C的方式类似传递数组作为指针,可变对象可以在函数中的适当位置改变,很像C阵列。

(编辑-布莱尔更新了他广受欢迎的答案,使其准确无误)

我认为重要的是要注意到,目前获得最多选票的帖子(布莱尔•康拉德),虽然其结果正确,但却具有误导性,并且根据其定义,几乎不正确。虽然有许多语言(如C)允许用户通过引用传递或通过值传递,但Python不是其中之一。

大卫·库尔纳波的回答指向了真正的答案,并解释了为什么布莱尔·康拉德帖子中的行为似乎是正确的,而定义却不正确。

在Python是按值传递的情况下,所有语言都按值传递,因为必须发送一些数据(无论是“值”还是“引用”)。然而,这并不意味着Python是按C程序员会想到的值传递的。

如果你想要这种行为,Blair Conrad的回答很好。但如果你想知道Python既不是通过值传递,也不是通过引用传递的根本原因,请阅读大卫·库尔纳波的答案。

简单答案:

在类似于python的c++中,当您创建一个对象实例并将其作为参数传递时,不会复制实例本身,因此您可以从函数的外部和内部引用相同的实例,并且可以修改相同对象实例的组件基准,因此外部可以看到更改。

对于基本类型,python和c++的行为也相同,因为现在创建了实例的副本,所以外部看到/修改的实例与函数内部不同。因此,外部看不到内部的变化。

下面是python和c++之间的真正区别:

c++具有地址指针的概念,而c++允许您传递指针,这绕过了对基本类型的复制,因此函数内部可以影响与外部相同的实例,因此外部也可以看到更改。这在python中没有等价的,因此如果没有变通方法(例如创建包装器类型)是不可能的。

这样的指针在python中很有用,但不像在c++中那样有必要,因为在c++中,您只能返回一个实体,而在python中,您可以返回用逗号分隔的多个值(即元组)。因此,在python中,如果您有变量a、b和c,并希望函数持久地修改它们(相对于外部),您可以这样做:

a=4
b=3
c=8

a,b,c=somefunc(a,b,c)
# a,b,c now have different values here

这样的语法在c++中是不容易实现的,因此在c++中您可以这样做:

int a=4
int b=3
int c=8
somefunc(&a,&b,&c)
// a,b,c now have different values here

我发现其他答案相当长而且复杂,所以我创建了这个简单的图来解释Python处理变量和参数的方式。