问题描述
Python 文档似乎不清楚参数是通过引用传递还是通过值传递,以下代码生成了未更改的值 'Original'
The Python documentation seems unclear about whether parameters are passed by reference or value, and the following code produces the unchanged value 'Original'
class PassByReference:
def __init__(self):
self.variable = 'Original'
self.change(self.variable)
print(self.variable)
def change(self, var):
var = 'Changed'
我可以通过实际引用传递变量吗?
Is there something I can do to pass the variable by actual reference?
推荐答案
参数是 通过赋值.这背后的原因有两个:
Arguments are passed by assignment. The rationale behind this is twofold:
- 传入的参数实际上是对对象的引用(但引用是按值传递的)
- 有些数据类型是可变的,但有些则不是
- the parameter passed in is actually a reference to an object (but the reference is passed by value)
- some data types are mutable, but others aren't
所以:
如果您将一个 可变 对象传递给一个方法,该方法将获得对同一对象的引用,并且您可以随心所欲地改变它,但是如果您在方法,外部作用域将对此一无所知,完成后,外部引用仍将指向原始对象.
If you pass a mutable object into a method, the method gets a reference to that same object and you can mutate it to your heart's delight, but if you rebind the reference in the method, the outer scope will know nothing about it, and after you're done, the outer reference will still point at the original object.
如果你将一个不可变对象传递给一个方法,你仍然不能重新绑定外部引用,你甚至不能改变对象.
If you pass an immutable object to a method, you still can't rebind the outer reference, and you can't even mutate the object.
为了更清楚,让我们举一些例子.
To make it even more clear, let's have some examples.
让我们尝试修改传递给方法的列表:
def try_to_change_list_contents(the_list):
print('got', the_list)
the_list.append('four')
print('changed to', the_list)
outer_list = ['one', 'two', 'three']
print('before, outer_list =', outer_list)
try_to_change_list_contents(outer_list)
print('after, outer_list =', outer_list)
输出:
before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']
由于传入的参数是对 outer_list
的引用,而不是它的副本,我们可以使用变异列表方法对其进行更改,并将更改反映在外部作用域中.
Since the parameter passed in is a reference to outer_list
, not a copy of it, we can use the mutating list methods to change it and have the changes reflected in the outer scope.
现在让我们看看当我们尝试更改作为参数传入的引用时会发生什么:
def try_to_change_list_reference(the_list):
print('got', the_list)
the_list = ['and', 'we', 'can', 'not', 'lie']
print('set to', the_list)
outer_list = ['we', 'like', 'proper', 'English']
print('before, outer_list =', outer_list)
try_to_change_list_reference(outer_list)
print('after, outer_list =', outer_list)
输出:
before, outer_list = ['we', 'like', 'proper', 'English']
got ['we', 'like', 'proper', 'English']
set to ['and', 'we', 'can', 'not', 'lie']
after, outer_list = ['we', 'like', 'proper', 'English']
由于the_list
参数是按值传递的,因此为它分配一个新列表对方法外的代码没有任何影响.the_list
是 outer_list
引用的副本,我们让 the_list
指向一个新列表,但是没有办法改变 outer_list
代码>outer_list 指向.
Since the the_list
parameter was passed by value, assigning a new list to it had no effect that the code outside the method could see. The the_list
was a copy of the outer_list
reference, and we had the_list
point to a new list, but there was no way to change where outer_list
pointed.
它是不可变的,所以我们无法改变字符串的内容
现在,让我们尝试更改引用
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
同样,由于 the_string
参数是按值传递的,因此为它分配一个新的字符串对方法外的代码没有任何影响.the_string
是 outer_string
引用的副本,我们让 the_string
指向一个新字符串,但是没有办法改变 outer_string
代码>outer_string 指向.
Again, since the the_string
parameter was passed by value, assigning a new string to it had no effect that the code outside the method could see. The the_string
was a copy of the outer_string
reference, and we had the_string
point to a new string, but there was no way to change where outer_string
pointed.
我希望这能让事情变得更清楚.
I hope this clears things up a little.
注意到这并没有回答@David 最初提出的问题,我可以做些什么来通过实际引用传递变量?".让我们继续努力.
It's been noted that this doesn't answer the question that @David originally asked, "Is there something I can do to pass the variable by actual reference?". Let's work on that.
正如@Andrea 的回答所示,您可以返回新值.这不会改变传递信息的方式,但确实可以让您获得所需的信息:
As @Andrea's answer shows, you could return the new value. This doesn't change the way things are passed in, but does let you get the information you want back out:
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)
如果您真的想避免使用返回值,您可以创建一个类来保存您的值并将其传递给函数或使用现有类,例如列表:
If you really wanted to avoid using a return value, you could create a class to hold your value and pass it into the function or use an existing class, like a list:
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])
虽然这看起来有点麻烦.
Although this seems a little cumbersome.
这篇关于如何通过引用传递变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!