How does the append method work in python?
The other two answers are great. I suggest you try to id
get the address.
See next example
def foo(x):
x.append (3)
print "global",id(x)
x = [8]
print "local ",id(x)
return x
x=[1, 5]
print "global",id(x)
y= foo(x)
print "global",id(x)
print x
print y
And the conclusion
global 140646798391920
global 140646798391920
local 140646798392928
global 140646798391920
[1, 5, 3]
[8]
As you can see, the address of the variable x
remains the same when you manipulate it, but changes with use =
. Moving a variable within a function makes the variable local to the function
source to share
You have a lot going on. So let go step by step.
x = [1,5]
You assign a list from 1.5 to x
y=foo(x)
You call foo and pass x and assign whatever is returned from foo
inside foo
you call x.append(3)
which adds 3 to the list that was passed in.
then set x = [8]
, which is now a reference to the local variable x, which is then returned from foo, ultimately settingy = [8]
source to share
Object references
The key to understanding this is that Python passes variables around using object references. They are similar to pointers in a language like C ++, but differ in very key ways.
When assignment is performed (using the assignment operator, =
):
x = [1, 5]
Actually 2 things were created. First, it's the object itself, which is a list [1, 5]
. This object is a separate object from the second object, which is a (global) object reference to the object.
Object(s) Object Reference(s)
[1, 5] x (global) <--- New object created
In python, objects are passed to functions by object reference; they are not passed "by reference" or "by value" as in C ++. This means that when x
passed to a function foo
, a new local object reference to the created object is created.
Object(s) Object Reference(s)
[1, 5] x (global), x (local to foo) <--- Now two object references
Now, internally, foo
we call x.append(3)
that directly modifies the object (called the reference to foo-local x object itself):
Object(s) Object Reference(s)
[1, 5, 3] x (global), x (local to foo) <--- Still two object references
Then we do something else. We assign the object reference local-foo x
(or reassign since the object reference already existed previously) in the NEW LIST .
Object(s) Object Reference(s)
[1, 5, 3] x (global) <--- One object reference remains
[8] x (local to foo) <--- New object created
Please note that the global object reference x
still exists! He was not influenced. We just reassigned the local-foo object reference to a x
NEW list.
Finally, it should be clear that when the function returns, we have this:
Object(s) Object Reference(s)
[1, 5, 3] x (global) <--- Unchanged
[8] y (global), x (local to foo) <--- New object reference created
Side panel
Note that the reference to the local-foo object x
still exists! This is an important behavior to understand, because if we do something like this:
def f(a = []):
a.append(1)
return a
f()
f()
f()
We will not receive:
[1]
[1]
[1]
Instead, we get:
[1]
[1, 1]
[1, 1, 1]
The statement a = []
is only evaluated by ONCE by the interpreter when the program is first run, and this object reference is never removed (unless we remove this function).
As a result, when called f()
, local-f a
does not fall back to []
. It "remembers" its previous meaning; this is because this local object reference is still valid (i.e., it has not been removed) and therefore the object does not get garbage collected between function calls.
Contrast with pointers
One way that object references differ from pointers is through assignment. If Python used actual pointers, you would expect behavior like:
a = 1 b = a b = 2 assert a == 2
However, this statement throws an error. The reason is that it b = 2
does NOT affect the object that the object reference points to, b. It creates a NEW object ( 2
) and reassigns to b
that object.
In other ways, object references differ from pointers in terms of deletion:
a = 1 b = a del a assert b is None
This statement also raises an error. The reason is the same as in the example above; del a
No effects on the object to which the link points to an object b
. He simply removes the reference to the object a
. The object reference b
and the object it points to 1
are not affected.
You might be asking, "Well, then how do you delete the actual object?" Answer: YOU CAN'T! You can remove all references to this object. As soon as there are no more references to the object, the object becomes garbage collection and it will be deleted for you (although you can force this to happen with a module gc
). This feature is known as memory management and it is one of the main advantages of Python, and it is also one of the reasons why Python uses object references in the first place.
Variability
Another thing to understand is that there are two types of objects: mutable and immutable. Mutable objects can be modified, and immutable objects cannot be modified.
A list
, such as [1, 5]
, is mutable. A tuple
or int
, on the other hand, is immutable.
Method append
Now that this is all clear, we should be able to answer the question "How does append
Python work?" The result of the method append()
is an operation on the most mutable list object. list
changed "in place" so to speak. Created a new list
one and then assigned foo-local x
. This is in contrast to the assignment operator =
, which creates a NEW object and assigns that object to an object reference.
source to share
The scope x
inside is foo
function specific and independent of the main calling context. x
inside foo
starts to refer to the same object as x
in the main context, because the parameter that was passed, but the moment you use the assignment operator to set it to [8]
, you have allocated a new object, which x
inside foo
indicates that now completely different from x
in the main context. To illustrate further, try changing foo
to this:
def foo(x):
print("Inside foo(): id(x) = " + str(id(x)))
x.append (3)
print("After appending: id(x) = " + str(id(x)))
x = [8]
print("After setting x to [8], id(x) = " + str(id(x)))
return x
When I executed I got this output:
Inside foo(): id(x) = 4418625336
After appending: id(x) = 4418625336
After setting x to [8], id(x) = 4418719896
[1, 5, 3]
[8]
(the ids you see will be different, but the point will still be clear, hopefully)
You can see that it is append
simply mutating an existing object - no need to allocate a new one. But as soon as the statement =
executes, the new object is selected (and eventually returned to the main context where it is assigned y
).
source to share