参数是通过引用传递还是通过值传递?如何通过引用传递,以便下面的代码输出“Changed”而不是“Original”?
class PassByReference:
def __init__(self):
self.variable = 'Original'
self.change(self.variable)
print(self.variable)
def change(self, var):
var = 'Changed'
另请参阅:为什么函数可以修改调用者感知的某些参数,而不能修改其他参数?
下面是Python中使用的pass by对象概念的简单解释(我希望)。每当您将对象传递给函数时,对象本身就会被传递(Python中的对象实际上是其他编程语言中的值),而不是对该对象的引用。换句话说,当您拨打电话时:
def change_me(list):
list = [1, 2, 3]
my_list = [0, 1]
change_me(my_list)
正在传递实际对象-[0,1](在其他编程语言中称为值)。因此,实际上函数change_me将尝试执行以下操作:
[0, 1] = [1, 2, 3]
这显然不会改变传递给函数的对象。如果函数看起来像这样:
def change_me(list):
list.append(2)
那么该调用将导致:
[0, 1].append(2)
这显然会改变对象。这个答案很好地解释了这一点。
Python中没有变量
理解参数传递的关键是停止思考“变量”。Python中有名称和对象看起来像变量,但始终区分这三个变量是有用的。
Python有名称和对象。赋值将名称绑定到对象。向函数传递参数还将名称(函数的参数名称)绑定到对象。
这就是它的全部。变异性与这个问题无关。
例子:
a = 1
这将名称a绑定到保存值1的integer类型的对象。
b = x
这将名称b绑定到名称x当前绑定到的同一对象。之后,名称b与名称x不再相关。
请参见Python 3语言参考中的3.1和4.2节。
如何阅读问题中的示例
在问题中显示的代码中,self.Change(self.variable)语句将名称var(在函数Change的作用域中)绑定到保存值“Original”的对象,赋值var='Changed'(在函数Change的主体中)再次将相同的名称分配给某个其他对象(恰好也包含字符串,但可能完全是其他对象)。
如何通过引用传递
因此,如果要更改的对象是可变对象,则没有问题,因为所有内容都是通过引用有效传递的。
如果它是一个不可变对象(例如布尔值、数字、字符串),那么方法是将它包装在一个可变对象中。对于这一点,快速而肮脏的解决方案是一个单元素列表(而不是self.variable,传递[self.variable]并在函数中修改var[0])。更像蟒蛇的方法是引入一个简单的单属性类。该函数接收类的实例并操作属性。
除了所有关于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