I wrote this class for testing:
class PassByReference: def __init__(self): self.variable = 'Original' self.change(self.variable) print(self.variable) def change(self, var): var = 'Changed'
When I try to create an instance, the output is original
. So parameters in python seem to be passed by value. Is that right? How to modify the code to achieve the effect of reference passing so that the output is changed
?
Sometimes people are surprised that code like x = 1
(where x
is the parameter name) does not affect the caller's parameters, but code like Code like x[0] = 1
will affect the caller's parameters. This happens because despite the =
syntax, item assignment and slice assignment are methods of mutating existing objects, while Not reassigning variables. See Why can a function modify some parameters as perceived by the caller, but not others? Learn more.
See also What is the difference between pass by reference and pass by value? For important, language-independent terminology discussions.
The parameters are passed by assignment. There are two reasons behind this:
so:
If you pass a mutable object to a method, the method will get a reference to the same object and you can change it however you want, but if you are in the outer scope of the method Knowing nothing about it, when you're done, the external reference will still be pointing to the original object.
If you pass an immutable object to a method, you still cannot rebind the external reference or even change the object.
To illustrate this more clearly, let's give some examples.
Let’s try modifying the list passed to the method:
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)
Output:
before, outer_list = ['one', 'two', 'three'] got ['one', 'two', 'three'] changed to ['one', 'two', 'three', 'four'] after, outer_list = ['one', 'two', 'three', 'four']
Since the parameter passed in is a reference to outer_list
and not a copy of it, we can use the mutate list method to change it and have the changes reflected in the outer scope.
Now let's see what happens when we try to change the reference passed in as a parameter:
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)
Output:
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']
Since the_list
parameter is passed by value, assigning it a new list will not have any impact on code outside the method. the_list
is a copy of the outer_list
reference, we have the_list
pointing to a new list, but there is no way to change where outer_list
points to.
It is immutable, so we cannot change the content of the string
Now, let’s try to change the reference
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)
Output:
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
Likewise, since the_string
parameter is passed by value, assigning it a new string will not have any visible effect on code outside the method. the_string
is a copy of the outer_string
reference, we have the_string
pointing to a new string, but there is no way to change the location outer_string
points to.
I hope this makes things clearer.
Edit: Someone pointed out that this doesn't answer the original question posed by @david: "Is there anything I can do to pass the variable by actual reference?". Let's work hard.
As @andrea's answer shows, you can return new values. This doesn't change how the content is passed in, but it allows you to get the information you want:
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 want to avoid using the return value, you can create a class to hold your value and pass it to the function or use an existing class, such as 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 bit troublesome.
The above is the detailed content of How to pass variable by reference?. For more information, please follow other related articles on the PHP Chinese website!