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

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

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

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


当前回答

给定python处理值和对它们的引用的方式,唯一可以引用任意实例属性的方法是通过名称:

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

    def change(self, var):
        self.__dict__[var] = 'Changed'

当然,在实际代码中,您可以在dict查找中添加错误检查。

其他回答

除了所有关于Python中这些东西的工作原理的精彩解释之外,我看不到任何关于这个问题的简单建议。就像您创建对象和实例一样,处理实例变量并更改它们的Python方式如下:

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

    def Change(self):
        self.variable = 'Changed'

在实例方法中,通常引用self来访问实例属性。在__init__中设置实例属性并在实例方法中读取或更改它们是正常的。这也是为什么将self-als作为第一个参数传递给def Change。

另一种解决方案是创建如下静态方法:

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

    @staticmethod
    def Change(var):
        var = 'Changed'
        return var

Python中的“通过引用”与C++/Java中的“引用传递”概念截然不同。

Java&C#:基元类型(包括字符串)通过值传递(副本),引用类型通过引用传递(地址副本),因此调用方可以看到调用函数中参数的所有更改。C++:允许通过引用或通过值传递。如果参数是通过引用传递的,则可以根据参数是否作为常量传递来修改它。但是,无论是否为常量,参数都保持对对象的引用,并且不能将引用指定为指向所调用函数中的其他对象。蟒蛇:Python是“按对象引用传递”,人们常说:“对象引用是按值传递的。”。调用者和函数都引用同一个对象,但函数中的参数是一个新变量,它只是在调用者中保存对象的副本。与C++一样,参数可以在函数中修改或不修改-这取决于传递的对象类型。如;不可变对象类型不能在调用的函数中修改,而可变对象可以更新或重新初始化。更新或重新分配/重新初始化可变变量之间的一个关键区别是,更新的值会在调用的函数中反映出来,而重新初始化的值则不会。将新对象分配给可变变量的作用域是python中函数的本地作用域。@blair conrad提供的例子很好地理解了这一点。

def i_my_wstring_length(wstring_input:str = "", i_length:int = 0) -> int:
    i_length[0] = len(wstring_input)
    return 0

wstring_test  = "Test message with 32 characters."
i_length_test = [0]
i_my_wstring_length(wstring_test, i_length_test)
print("The string:\n\"{}\"\ncontains {} character(s).".format(wstring_test, *i_length_test))
input("\nPress ENTER key to continue . . . ")

在这种情况下,方法Change中名为var的变量被分配了对self.variable的引用,并且您立即将字符串分配给var。它不再指向self.variable.下面的代码片段显示了如果您修改了var和self.variaable指向的数据结构(在本例中是一个列表)会发生什么:

>>> class PassByReference:
...     def __init__(self):
...         self.variable = ['Original']
...         self.change(self.variable)
...         print self.variable
...         
...     def change(self, var):
...         var.append('Changed')
... 
>>> q = PassByReference()
['Original', 'Changed']
>>> 

我相信其他人可以进一步澄清这一点。

我通常使用的一个简单技巧是将其包装在列表中:

def Change(self, var):
    var[0] = 'Changed'

variable = ['Original']
self.Change(variable)      
print variable[0]

(是的,我知道这可能很不方便,但有时这样做很简单。)