def try_to_change_string_reference(the_string):
print('got', the_string)
the_string = 'In a kingdom by the sea'
print('set to', the_string)
outer_string = 'It was many and many a year ago'
print('before, outer_string =', outer_string)
try_to_change_string_reference(outer_string)
print('after, outer_string =', outer_string)
输出:
before, outer_string = It was many and many a year ago
got It was many and many a year ago
set to In a kingdom by the sea
after, outer_string = It was many and many a year ago
def return_a_whole_new_string(the_string):
new_string = something_to_do_with_the_old_string(the_string)
return new_string
# then you could call it like
my_string = return_a_whole_new_string(my_string)
def use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change):
new_string = something_to_do_with_the_old_string(stuff_to_change[0])
stuff_to_change[0] = new_string
# then you could call it like
wrapper = [my_string]
use_a_wrapper_to_simulate_pass_by_reference(wrapper)
do_something_with(wrapper[0])
我发现其他的答案很长很复杂,所以我创建了这个简单的图表来解释Python处理变量和参数的方式。
这个问题来自于对Python中的变量的误解。如果你习惯了大多数传统语言,你就有了一个心理模型,可以按照以下顺序来描述发生的事情:
您认为
a
是存储值1
的内存位置,然后更新为存储值2
。这不是Python中的工作方式。相反,a
以对值为1
的对象的引用开始,然后被重新分配为对值为2
的对象的引用。即使a
不再引用第一个对象,这两个对象也可能继续共存;事实上,程序中的任何其他引用都可以共享它们。使用参数调用函数时,将创建引用传入对象的新引用。这与函数调用中使用的引用不同,因此无法更新该引用并使其引用新对象。在您的示例中:
self.variable
是对字符串对象'Original'
的引用。当您调用Change
时,您将创建对对象的第二个引用var
。在函数内部,您将引用var
重新分配给不同的字符串对象'Changed'
,但引用self.variable
是独立的,不会更改。唯一的办法就是传递一个可变对象。因为这两个引用引用同一个对象,所以对该对象的任何更改都将反映在这两个位置。
参数是passed by assignment。这背后的理由有两个:
所以:
如果你把一个可变的对象传给一个方法,这个方法会得到一个对同一个对象的引用,你可以让它发生变化,让你高兴,但是如果你在这个方法中重新绑定引用,外部作用域对它一无所知,完成后,外部引用仍然指向原始对象。
如果将不可变的对象传递给方法,则仍然无法重新绑定外部引用,甚至无法对该对象进行变异。
为了更清楚地说明这一点,让我们举几个例子。
List-可变类型
让我们尝试修改传递给方法的列表:
输出:
因为传入的参数是对
outer_list
的引用,而不是它的副本,所以我们可以使用变异列表方法来更改它,并将更改反映在外部作用域中。现在让我们看看当我们试图更改作为参数传入的引用时会发生什么:
输出:
由于
the_list
参数是按值传递的,因此给它分配一个新列表并没有方法外部的代码可以看到的效果。the_list
是outer_list
引用的副本,我们有一个指向新列表的the_list
点,但是无法更改outer_list
点的位置。String-不可变类型
它是不可变的,因此我们无法更改字符串的内容
现在,让我们尝试更改引用
输出:
同样,由于
the_string
参数是按值传递的,因此给它分配一个新字符串没有方法外部的代码可以看到的效果。the_string
是outer_string
引用的副本,我们有一个指向新字符串的the_string
点,但是无法更改outer_string
点的位置。我希望这能澄清一些事情。
编辑:我们注意到,这并不能回答@David最初提出的问题:“有什么我可以做的,通过实际引用传递变量吗?”。让我们继续努力吧。
我们该怎么解决这个问题?
正如@Andrea的答案所示,您可以返回新值。这不会改变传递信息的方式,但会让您获得想要的信息:
如果您真的想避免使用返回值,可以创建一个类来保存您的值并将其传递到函数中,或者使用现有的类,如列表:
虽然这看起来有点麻烦。
相关问题 更多 >
编程相关推荐