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

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

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

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


当前回答

简单答案:

在类似于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

其他回答

可以用[]传递

dta=“15252”正文=[dta]

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

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' )

除了所有关于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

大多数时候,要通过引用传递的变量是类成员。我建议的解决方案是使用修饰符来添加可变字段和相应的属性。该字段是变量的类包装器。

@refproperty同时添加self_myvar(可变)和self.myvar属性。

@refproperty('myvar')
class T():
    pass

def f(x):
   x.value=6

y=T()
y.myvar=3
f(y._myvar)
print(y.myvar) 

它将打印6。

将其与以下内容进行比较:

class X:
   pass

x=X()
x.myvar=4

def f(y):
    y=6

f(x.myvar)
print(x.myvar) 

在这种情况下,它不起作用。它将打印4。

代码如下:

def refproperty(var,value=None):
    def getp(self):
        return getattr(self,'_'+var).get(self)

    def setp(self,v):
        return getattr(self,'_'+var).set(self,v)

    def decorator(klass):
        orginit=klass.__init__
        setattr(klass,var,property(getp,setp))

        def newinit(self,*args,**kw):
            rv=RefVar(value)
            setattr(self,'_'+var,rv)
            orginit(self,*args,**kw)

        klass.__init__=newinit
        return klass
    return decorator

class RefVar(object):
    def __init__(self, value=None):
        self.value = value
    def get(self,*args):
        return self.value
    def set(self,main, value):
        self.value = value

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

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

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

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