参数是通过引用传递还是通过值传递?如何通过引用传递,以便下面的代码输出“Changed”而不是“Original”?
class PassByReference:
def __init__(self):
self.variable = 'Original'
self.change(self.variable)
print(self.variable)
def change(self, var):
var = 'Changed'
另请参阅:为什么函数可以修改调用者感知的某些参数,而不能修改其他参数?
从技术上讲,Python始终使用引用传递值。我将重复我的另一个回答,以支持我的发言。
Python始终使用引用传递值。没有任何例外。任何变量赋值都意味着复制参考值。没有例外。任何变量都是绑定到引用值的名称。总是
您可以将参考值视为目标对象的地址。地址在使用时自动取消引用。这样,使用引用值时,似乎可以直接使用目标对象。但在两者之间总是有一个参考点,多跳一步就可以到达目标。
下面的示例证明了Python使用的是通过引用传递:
如果参数是按值传递的,则无法修改外部lst。绿色是目标对象(黑色是存储在内存中的值,红色是对象类型),黄色是内存中的参考值,如箭头所示。蓝色实心箭头是传递给函数的参考值(通过蓝色虚线箭头路径)。丑陋的深黄色是内部字典。(实际上它也可以画成一个绿色椭圆。颜色和形状只表示它是内部的。)
您可以使用id()内置函数来了解引用值是什么(即目标对象的地址)。
在编译语言中,变量是能够捕获类型值的内存空间。在Python中,变量是绑定到引用变量的名称(内部捕获为字符串),该引用变量保存目标对象的引用值。变量的名称是内部字典中的键,该字典项的值部分存储目标的引用值。
引用值在Python中隐藏。没有任何用于存储引用值的显式用户类型。但是,您可以使用列表元素(或任何其他合适容器类型的元素)作为引用变量,因为所有容器都将元素存储为对目标对象的引用。换句话说,元素实际上不包含在容器中——只有对元素的引用。
(编辑-布莱尔更新了他广受欢迎的答案,使其准确无误)
我认为重要的是要注意到,目前获得最多选票的帖子(布莱尔•康拉德),虽然其结果正确,但却具有误导性,并且根据其定义,几乎不正确。虽然有许多语言(如C)允许用户通过引用传递或通过值传递,但Python不是其中之一。
大卫·库尔纳波的回答指向了真正的答案,并解释了为什么布莱尔·康拉德帖子中的行为似乎是正确的,而定义却不正确。
在Python是按值传递的情况下,所有语言都按值传递,因为必须发送一些数据(无论是“值”还是“引用”)。然而,这并不意味着Python是按C程序员会想到的值传递的。
如果你想要这种行为,Blair Conrad的回答很好。但如果你想知道Python既不是通过值传递,也不是通过引用传递的根本原因,请阅读大卫·库尔纳波的答案。
关于这一点,已经有很多很好的答案(或者说是观点),我已经读过了,但我想提到一个缺失的答案。常见问题解答部分Python文档中的一个。我不知道发布此页面的日期,但这应该是我们的真实参考:
记住,在Python中,参数是通过赋值传递的。自从赋值只创建对对象的引用,没有别名在调用者和被调用者中的参数名之间,因此没有引用调用本身。
如果您有:
a = SOMETHING
def fn(arg):
pass
你把它叫做fn(a),你做的和你在作业中做的完全一样。所以会发生这种情况:
arg = a
创建了对SOMETHING的其他引用。变量只是符号/名称/引用。他们不“持有”任何东西。
大多数时候,要通过引用传递的变量是类成员。我建议的解决方案是使用修饰符来添加可变字段和相应的属性。该字段是变量的类包装器。
@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