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?
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])
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
So:
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.
List – a mutable type
Let’s try to modify the list that was passed to a method:
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.
Now let’s see what happens when we try to change the reference that was passed in as a parameter:
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.
String – an immutable type
It’s immutable, so there’s nothing we can do to change the contents 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
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.
EDIT: 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.
How do we get around this?
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])
The problem comes from a misunderstanding of what variables are in Python. If you’re used to most traditional languages, you have a mental model of what happens in the following sequence:
a = 1
a = 2
You believe that a is a memory location that stores the value 1, then is updated to store the value 2. That’s not how things work in Python. Rather, a starts as a reference to an object with the value 1, then gets reassigned as a reference to an object with the value 2. Those two objects may continue to coexist even though a doesn’t refer to the first one anymore; in fact they may be shared by any number of other references within the program.
When you call a function with a parameter, a new reference is created that refers to the object passed in. This is separate from the reference that was used in the function call, so there’s no way to update that reference and make it refer to a new object. In your example:
self.variable is a reference to the string object 'Original'. When you call Change you create a second reference var to the object. Inside the function you reassign the reference var to a different string object 'Changed', but the reference self.variable is separate and does not change.
The only way around this is to pass a mutable object. Because both references refer to the same object, any changes to the object are reflected in both places.
“…variables [names] are not objects; they cannot be denoted by other variables or referred to by objects.”
In your example, when the Change method is called–a namespace is created for it; and var becomes a name, within that namespace, for the string object 'Original'. That object then has a name in two namespaces. Next, var = 'Changed' binds var to a new string object, and thus the method’s namespace forgets about 'Original'. Finally, that namespace is forgotten, and the string 'Changed' along with it.
Think of stuff being passed by assignment instead of by reference/by value. That way, it is always clear, what is happening as long as you understand what happens during the normal assignment.
So, when passing a list to a function/method, the list is assigned to the parameter name. Appending to the list will result in the list being modified. Reassigning the list inside the function will not change the original list, since:
a = [1, 2, 3]
b = a
b.append(4)
b = ['a', 'b']
print a, b # prints [1, 2, 3, 4] ['a', 'b']
Since immutable types cannot be modified, they seem like being passed by value – passing an int into a function means assigning the int to the function’s parameter. You can only ever reassign that, but it won’t change the original variables value.
Objects are allocated on the heap and pointers to them can be passed around anywhere.
When you make an assignment such as x = 1000, a dictionary entry is created that maps the string “x” in the current namespace to a pointer to the integer object containing one thousand.
When you update “x” with x = 2000, a new integer object is created and the dictionary is updated to point at the new object. The old one thousand object is unchanged (and may or may not be alive depending on whether anything else refers to the object).
When you do a new assignment such as y = x, a new dictionary entry “y” is created that points to the same object as the entry for “x”.
Objects like strings and integers are immutable. This simply means that there are no methods that can change the object after it has been created. For example, once the integer object one-thousand is created, it will never change. Math is done by creating new integer objects.
Objects like lists are mutable. This means that the contents of the object can be changed by anything pointing to the object. For example, x = []; y = x; x.append(10); print y will print [10]. The empty list was created. Both “x” and “y” point to the same list. The append method mutates (updates) the list object (like adding a record to a database) and the result is visible to both “x” and “y” (just as a database update would be visible to every connection to that database).
Technically, Python always uses pass by reference values. I am going to repeat my other answer to support my statement.
Python always uses pass-by-reference values. There isn’t any exception. Any variable assignment means copying the reference value. No exception. Any variable is the name bound to the reference value. Always.
You can think about a reference value as the address of the target object. The address is automatically dereferenced when used. This way, working with the reference value, it seems you work directly with the target object. But there always is a reference in between, one step more to jump to the target.
Here is the example that proves that Python uses passing by reference:
If the argument was passed by value, the outer lst could not be modified. The green are the target objects (the black is the value stored inside, the red is the object type), the yellow is the memory with the reference value inside — drawn as the arrow. The blue solid arrow is the reference value that was passed to the function (via the dashed blue arrow path). The ugly dark yellow is the internal dictionary. (It actually could be drawn also as a green ellipse. The colour and the shape only says it is internal.)
You can use the id() built-in function to learn what the reference value is (that is, the address of the target object).
In compiled languages, a variable is a memory space that is able to capture the value of the type. In Python, a variable is a name (captured internally as a string) bound to the reference variable that holds the reference value to the target object. The name of the variable is the key in the internal dictionary, the value part of that dictionary item stores the reference value to the target.
Reference values are hidden in Python. There isn’t any explicit user type for storing the reference value. However, you can use a list element (or element in any other suitable container type) as the reference variable, because all containers do store the elements also as references to the target objects. In other words, elements are actually not contained inside the container — only the references to elements are.
The key to understanding parameter passing is to stop thinking about “variables”. There are names and objects in Python and together they
appear like variables, but it is useful to always distinguish the three.
Python has names and objects.
Assignment binds a name to an object.
Passing an argument into a function also binds a name (the parameter name of the function) to an object.
That is all there is to it. Mutability is irrelevant to this question.
Example:
a = 1
This binds the name a to an object of type integer that holds the value 1.
b = x
This binds the name b to the same object that the name x is currently bound to.
Afterward, the name b has nothing to do with the name x anymore.
See sections 3.1 and 4.2 in the Python 3 language reference.
How to read the example in the question
In the code shown in the question, the statement self.Change(self.variable) binds the name var (in the scope of function Change) to the object that holds the value 'Original' and the assignment var = 'Changed' (in the body of function Change) assigns that same name again: to some other object (that happens to hold a string as well but could have been something else entirely).
How to pass by reference
So if the thing you want to change is a mutable object, there is no problem, as everything is effectively passed by reference.
If it is an immutable object (e.g. a bool, number, string), the way to go is to wrap it in a mutable object.
The quick-and-dirty solution for this is a one-element list (instead of self.variable, pass [self.variable] and in the function modify var[0]).
The more pythonic approach would be to introduce a trivial, one-attribute class. The function receives an instance of the class and manipulates the attribute.
(edit – Blair has updated his enormously popular answer so that it is now accurate)
I think it is important to note that the current post with the most votes (by Blair Conrad), while being correct with respect to its result, is misleading and is borderline incorrect based on its definitions. While there are many languages (like C) that allow the user to either pass by reference or pass by value, Python is not one of them.
David Cournapeau’s answer points to the real answer and explains why the behavior in Blair Conrad’s post seems to be correct while the definitions are not.
To the extent that Python is pass by value, all languages are pass by value since some piece of data (be it a “value” or a “reference”) must be sent. However, that does not mean that Python is pass by value in the sense that a C programmer would think of it.
If you want the behavior, Blair Conrad’s answer is fine. But if you want to know the nuts and bolts of why Python is neither pass by value or pass by reference, read David Cournapeau’s answer.
回答 10
您在这里得到了一些非常好的答案。
x =[2,4,4,5,5]print x # 2, 4, 4, 5, 5def go( li ):
li =[5,6,7,8]# re-assigning what li POINTS TO, does not# change the value of the ORIGINAL variable x
go( x )print x # 2, 4, 4, 5, 5 [ STILL! ]
raw_input('press any key to continue')
x = [ 2, 4, 4, 5, 5 ]
print x # 2, 4, 4, 5, 5
def go( li ) :
li = [ 5, 6, 7, 8 ] # re-assigning what li POINTS TO, does not
# change the value of the ORIGINAL variable x
go( x )
print x # 2, 4, 4, 5, 5 [ STILL! ]
raw_input( 'press any key to continue' )
In this case the variable titled var in the method Change is assigned a reference to self.variable, and you immediately assign a string to var. It’s no longer pointing to self.variable. The following code snippet shows what would happen if you modify the data structure pointed to by var and self.variable, in this case a list:
Python’s pass-by-assignment scheme isn’t quite the same as C++’s reference parameters option, but it turns out to be very similar to the argument-passing model of the C language (and others) in practice:
Immutable arguments are effectively passed “by value.” Objects such as integers and strings are passed by object reference instead of by copying, but because you can’t change immutable objects in place anyhow, the effect is much like making a copy.
Mutable arguments are effectively passed “by pointer.” Objects such as lists
and dictionaries are also passed by object reference, which is similar to the way C
passes arrays as pointers—mutable objects can be changed in place in the function,
much like C arrays.
>>>def x(y):...global z
... z = y
...>>> x
<function x at 0x00000000020E1730>>>> y
Traceback(most recent call last):File"<stdin>", line 1,in<module>NameError: name 'y'isnot defined
>>> z
Traceback(most recent call last):File"<stdin>", line 1,in<module>NameError: name 'z'isnot defined
>>> x(2)>>> x
<function x at 0x00000000020E1730>>>> y
Traceback(most recent call last):File"<stdin>", line 1,in<module>NameError: name 'y'isnot defined
>>> z
2
As you can state you need to have a mutable object, but let me suggest you to check over the global variables as they can help you or even solve this kind of issue!
>>> def x(y):
... global z
... z = y
...
>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'z' is not defined
>>> x(2)
>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
2
def test(l):print"Received", l , id(l)
l =[0,0,0]print"Changed to", l, id(l)# New local object created, breaking link to global l
l=[1,2,3]print"Original", l, id(l)
test(l)print"After", l, id(l)
给出:
Original[1,2,3]4454645632Received[1,2,3]4454645632Changed to [0,0,0]4474591928After[1,2,3]4454645632
“In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a new value anywhere within the function’s body, it’s assumed to be a local. If a variable is ever assigned a new value inside the function, the variable is implicitly local, and you need to explicitly declare it as ‘global’.
Though a bit surprising at first, a moment’s consideration explains this. On one hand, requiring global for assigned variables provides a bar against unintended side-effects. On the other hand, if global was required for all global references, you’d be using global all the time. You’d have to declare as global every reference to a built-in function or to a component of an imported module. This clutter would defeat the usefulness of the global declaration for identifying side-effects.”
Even when passing a mutable object to a function this still applies. And to me clearly explains the reason for the difference in behavior between assigning to the object and operating on the object in the function.
def test(l):
print "Received", l , id(l)
l = [0, 0, 0]
print "Changed to", l, id(l) # New local object created, breaking link to global l
l= [1,2,3]
print "Original", l, id(l)
test(l)
print "After", l, id(l)
gives:
Original [1, 2, 3] 4454645632
Received [1, 2, 3] 4454645632
Changed to [0, 0, 0] 4474591928
After [1, 2, 3] 4454645632
The assignment to an global variable that is not declared global therefore creates a new local object and breaks the link to the original object.
回答 15
这是pass by objectPython中使用的概念的简单解释(我希望如此)。
每当将对象传递给函数时,都会传递对象本身(Python中的对象实际上是您在其他编程语言中称为值的对象),而不是对该对象的引用。换句话说,当您调用时:
def change_me(list):
list =[1,2,3]
my_list =[0,1]
change_me(my_list)
Here is the simple (I hope) explanation of the concept pass by object used in Python.
Whenever you pass an object to the function, the object itself is passed (object in Python is actually what you’d call a value in other programming languages) not the reference to this object. In other words, when you call:
The actual object – [0, 1] (which would be called a value in other programming languages) is being passed. So in fact the function change_me will try to do something like:
[0, 1] = [1, 2, 3]
which obviously will not change the object passed to the function. If the function looked like this:
def change_me(list):
list.append(2)
Then the call would result in:
[0, 1].append(2)
which obviously will change the object. This answer explains it well.
Aside from all the great explanations on how this stuff works in Python, I don’t see a simple suggestion for the problem. As you seem to do create objects and instances, the pythonic way of handling instance variables and changing them is the following:
In instance methods, you normally refer to self to access instance attributes. It is normal to set instance attributes in __init__ and read or change them in instance methods. That is also why you pass self als the first argument to def Change.
Another solution would be to create a static method like this:
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
回答 17
即使该语言无法实现通过引用传递对象的小技巧,它也适用于Java,它是包含一项的列表。;-)
classPassByReference:def __init__(self, name):
self.name = name
def changeRef(ref):
ref[0]=PassByReference('Michael')
obj =PassByReference('Peter')print obj.name
p =[obj]# A pointer to obj! ;-)
changeRef(p)print p[0].name # p->name
There is a little trick to pass an object by reference, even though the language doesn’t make it possible. It works in Java too, it’s the list with one item. ;-)
class PassByReference:
def __init__(self, name):
self.name = name
def changeRef(ref):
ref[0] = PassByReference('Michael')
obj = PassByReference('Peter')
print obj.name
p = [obj] # A pointer to obj! ;-)
changeRef(p)
print p[0].name # p->name
I used the following method to quickly convert a couple of Fortran codes to Python. True, it’s not pass by reference as the original question was posed, but is a simple work around in some cases.
classByRef:def __init__(self, r, w, d):
self._read = r
self._write = w
self._delete = d
def set(self, val):
self._write(val)def get(self):return self._read()def remove(self):
self._delete()
wrapped = property(get, set, remove)# left as an exercise for the reader: define set, get, remove as local functions using global / nonlocal
r =ByRef(get, set, remove)
r.wrapped =15
While pass by reference is nothing that fits well into python and should be rarely used there are some workarounds that actually can work to get the object currently assigned to a local variable or even reassign a local variable from inside of a called function.
The basic idea is to have a function that can do that access and can be passed as object into other functions or stored in a class.
One way is to use global (for global variables) or nonlocal (for local variables in a function) in a wrapper function.
def change(wrapper):
wrapper(7)
x = 5
def setter(val):
global x
x = val
print(x)
The same idea works for reading and deleting a variable.
For just reading there is even a shorter way of just using lambda: x which returns a callable that when called returns the current value of x. This is somewhat like “call by name” used in languages in the distant past.
Passing 3 wrappers to access a variable is a bit unwieldy so those can be wrapped into a class that has a proxy attribute:
class ByRef:
def __init__(self, r, w, d):
self._read = r
self._write = w
self._delete = d
def set(self, val):
self._write(val)
def get(self):
return self._read()
def remove(self):
self._delete()
wrapped = property(get, set, remove)
# left as an exercise for the reader: define set, get, remove as local functions using global / nonlocal
r = ByRef(get, set, remove)
r.wrapped = 15
Pythons “reflection” support makes it possible to get a object that is capable of reassigning a name/variable in a given scope without defining functions explicitly in that scope:
class ByRef:
def __init__(self, locs, name):
self._locs = locs
self._name = name
def set(self, val):
self._locs[self._name] = val
def get(self):
return self._locs[self._name]
def remove(self):
del self._locs[self._name]
wrapped = property(get, set, remove)
def change(x):
x.wrapped = 7
def test_me():
x = 6
print(x)
change(ByRef(locals(), "x"))
print(x)
Here the ByRef class wraps a dictionary access. So attribute access to wrapped is translated to a item access in the passed dictionary. By passing the result of the builtin locals and the name of a local variable this ends up accessing a local variable. The python documentation as of 3.5 advises that changing the dictionary might not work but it seems to work for me.
in real code you would, of course, add error checking on the dict lookup.
回答 21
由于字典是通过引用传递的,因此可以使用dict变量在其中存储任何引用的值。
# returns the result of adding numbers `a` and `b`defAddNumbers(a, b, ref):# using a dict for reference
result = a + b
ref['multi']= a * b # reference the multi. ref['multi'] is number
ref['msg']="The result: "+ str(result)+" was nice!"# reference any string (errors, e.t.c). ref['msg'] is stringreturn result # return the sum
number1 =5
number2 =10
ref ={}# init a dict like that so it can save all the referenced values. this is because all dictionaries are passed by reference, while strings and numbers do not.
sum =AddNumbers(number1, number2, ref)print("sum: ", sum)# the return valueprint("multi: ", ref['multi'])# a referenced valueprint("msg: ", ref['msg'])# a referenced value
Since dictionaries are passed by reference, you can use a dict variable to store any referenced values inside it.
# returns the result of adding numbers `a` and `b`
def AddNumbers(a, b, ref): # using a dict for reference
result = a + b
ref['multi'] = a * b # reference the multi. ref['multi'] is number
ref['msg'] = "The result: " + str(result) + " was nice!" # reference any string (errors, e.t.c). ref['msg'] is string
return result # return the sum
number1 = 5
number2 = 10
ref = {} # init a dict like that so it can save all the referenced values. this is because all dictionaries are passed by reference, while strings and numbers do not.
sum = AddNumbers(number1, number2, ref)
print("sum: ", sum) # the return value
print("multi: ", ref['multi']) # a referenced value
print("msg: ", ref['msg']) # a referenced value
Pass-By-Reference in Python is quite different from the concept of pass by reference in C++/Java.
Java&C#: primitive types(include string)pass by value(copy), Reference type is passed by reference(address copy) so all changes made in the parameter in the called function are visible to the caller.
C++: Both pass-by-reference or pass-by-value are allowed. If a parameter is passed by reference, you can either modify it or not depending upon whether the parameter was passed as const or not. However, const or not, the parameter maintains the reference to the object and reference cannot be assigned to point to a different object within the called function.
Python:
Python is “pass-by-object-reference”, of which it is often said: “Object references are passed by value.”[Read here]1. Both the caller and the function refer to the same object but the parameter in the function is a new variable which is just holding a copy of the object in the caller. Like C++, a parameter can be either modified or not in function – This depends upon the type of object passed. eg; An immutable object type cannot be modified in the called function whereas a mutable object can be either updated or re-initialized. A crucial difference between updating or re-assigning/re-initializing the mutable variable is that updated value gets reflected back in the called function whereas the reinitialized value does not. Scope of any assignment of new object to a mutable variable is local to the function in the python. Examples provided by @blair-conrad are great to understand this.
回答 23
由于您的示例碰巧是面向对象的,因此可以进行以下更改以获得相似的结果:
classPassByReference:def __init__(self):
self.variable ='Original'
self.change('variable')print(self.variable)def change(self, var):
setattr(self, var,'Changed')# o.variable will equal 'Changed'
o =PassByReference()assert o.variable =='Changed'
Since your example happens to be object-oriented, you could make the following change to achieve a similar result:
class PassByReference:
def __init__(self):
self.variable = 'Original'
self.change('variable')
print(self.variable)
def change(self, var):
setattr(self, var, 'Changed')
# o.variable will equal 'Changed'
o = PassByReference()
assert o.variable == 'Changed'
回答 24
您只能将一个空类用作存储参考对象的实例,因为内部对象属性存储在实例字典中。参见示例。
classRefsObj(object):"A class which helps to create references to variables."pass...# an example of usagedef change_ref_var(ref_obj):
ref_obj.val =24
ref_obj =RefsObj()
ref_obj.val =1print(ref_obj.val)# or print ref_obj.val for python2
change_ref_var(ref_obj)print(ref_obj.val)
You can merely use an empty class as an instance to store reference objects because internally object attributes are stored in an instance dictionary. See the example.
class RefsObj(object):
"A class which helps to create references to variables."
pass
...
# an example of usage
def change_ref_var(ref_obj):
ref_obj.val = 24
ref_obj = RefsObj()
ref_obj.val = 1
print(ref_obj.val) # or print ref_obj.val for python2
change_ref_var(ref_obj)
print(ref_obj.val)
def need_to_modify(update):
update(42)# set new value 42# other codedef call_it():
value =21def update_value(new_value):nonlocal value
value = new_value
need_to_modify(update_value)print(value)# prints 42
Since it seems to be nowhere mentioned an approach to simulate references as known from e.g. C++ is to use an “update” function and pass that instead of the actual variable (or rather, “name”):
def need_to_modify(update):
update(42) # set new value 42
# other code
def call_it():
value = 21
def update_value(new_value):
nonlocal value
value = new_value
need_to_modify(update_value)
print(value) # prints 42
This is mostly useful for “out-only references” or in a situation with multiple threads / processes (by making the update function thread / multiprocessing safe).
Obviously the above does not allow reading the value, only updating it.