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

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

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

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


当前回答

想想通过赋值而不是通过引用/值传递的东西。这样,只要你明白在正常任务中发生了什么,就会很清楚发生了什么。

因此,当将列表传递给函数/方法时,该列表被分配给参数名称。附加到列表将导致列表被修改。重新分配函数内的列表不会更改原始列表,因为:

a = [1, 2, 3]
b = a
b.append(4)
b = ['a', 'b']
print a, b      # prints [1, 2, 3, 4] ['a', 'b']

由于不可变类型不能被修改,它们看起来像是通过值传递的——将int传递给函数意味着将int分配给函数的参数。您只能重新分配它,但它不会更改原始变量值。

其他回答

关于这一点,已经有很多很好的答案(或者说是观点),我已经读过了,但我想提到一个缺失的答案。常见问题解答部分Python文档中的一个。我不知道发布此页面的日期,但这应该是我们的真实参考:

记住,在Python中,参数是通过赋值传递的。自从赋值只创建对对象的引用,没有别名在调用者和被调用者中的参数名之间,因此没有引用调用本身。

如果您有:

a = SOMETHING

def fn(arg):
    pass

你把它叫做fn(a),你做的和你在作业中做的完全一样。所以会发生这种情况:

arg = a

创建了对SOMETHING的其他引用。变量只是符号/名称/引用。他们不“持有”任何东西。

由于您的示例恰好是面向对象的,因此可以进行以下更改以获得类似的结果:

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

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

# o.variable will equal 'Changed'
o = PassByReference()
assert o.variable == 'Changed'

或者,你可以使用看起来像这样的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整数,并且通过引用传递。然而,你必须小心,因为可能会发生奇怪的事情,因此不建议

你在这里得到了一些非常好的答案。

x = [ 2, 4, 4, 5, 5 ]
print x  # 2, 4, 4, 5, 5

def go( li ) :
  li = [ 5, 6, 7, 8 ]  # re-assigning what li POINTS TO, does not
  # change the value of the ORIGINAL variable x

go( x ) 
print x  # 2, 4, 4, 5, 5  [ STILL! ]


raw_input( 'press any key to continue' )

我分享了另一种有趣的方式,让人们通过一个方便的工具来理解这个主题——基于@Mark Ransom传递可变列表的示例,可视化巨蟒代码执行

随便玩玩,你就会明白的。

传递字符串

传递列表