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

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

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

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


当前回答

我解决了类似的要求,如下所示:

要实现更改变量的成员函数,请不要传递变量本身,而是传递包含引用该变量的setattr的functools.partial。在change()内调用functools.partial将执行setttr并更改实际引用的变量。

注意,setattr需要变量的名称作为字符串。

class PassByReference(object):
    def __init__(self):
        self.variable = "Original"
        print(self.variable)        
        self.change(partial(setattr,self,"variable"))
        print(self.variable)

    def change(self, setter):
        setter("Changed")

其他回答

正如你所说的,你需要一个可变的对象,但我建议你检查全局变量,因为它们可以帮助你甚至解决这类问题!

http://docs.python.org/3/faq/programming.html#what-是python中局部和全局变量的规则

例子:

>>> def x(y):
...     global z
...     z = y
...

>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'z' is not defined

>>> x(2)
>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
2

这里的答案有很多见解,但我认为这里没有明确提到另外一点。引用python文档https://docs.python.org/2/faq/programming.html#what-是python中局部和全局变量的规则

“在Python中,仅在函数内部引用的变量是隐式全局的。如果在函数体中的任何位置为变量分配了新值,则假定该变量是局部的。如果变量在函数内部被分配了新的值,则该变量隐式是局部的,您需要将其显式声明为“全局”。虽然一开始有点令人惊讶,但片刻的考虑可以解释这一点。一方面,要求全局分配变量可以防止意外的副作用。另一方面,如果所有全局引用都需要全局引用,那么您将一直使用全局引用。您必须将对内置函数或导入模块组件的每个引用声明为全局引用。这种混乱将破坏全球宣言在确定副作用方面的作用。"

即使在将可变对象传递给函数时,这仍然适用。对我来说,这清楚地解释了分配给对象和在函数中操作对象之间行为差异的原因。

def test(l):
    print "Received", l , id(l)
    l = [0, 0, 0]
    print "Changed to", l, id(l)  # New local object created, breaking link to global l

l= [1,2,3]
print "Original", l, id(l)
test(l)
print "After", l, id(l)

给予:

Original [1, 2, 3] 4454645632
Received [1, 2, 3] 4454645632
Changed to [0, 0, 0] 4474591928
After [1, 2, 3] 4454645632

因此,对未声明为全局的全局变量的赋值将创建一个新的局部对象,并断开与原始对象的链接。

在这种情况下,方法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']
>>> 

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

由于似乎没有任何地方提到过模拟引用的方法,例如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

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

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

可以用[]传递

dta=“15252”正文=[dta]