A difficulty with lists

M

Mok-Kong Shen

I ran the following code:

def xx(nlist):
print("begin: ",nlist)
nlist+=[999]
print("middle:",nlist)
nlist=nlist[:-1]
print("final: ",nlist)

u=[1,2,3,4]
print(u)
xx(u)
print(u)

and obtained the following result:

[1, 2, 3, 4]
begin: [1, 2, 3, 4]
middle: [1, 2, 3, 4, 999]
final: [1, 2, 3, 4]
[1, 2, 3, 4, 999]

As beginner I couldn't understand why the last line wasn't [1, 2, 3, 4].
Could someone kindly help?

M. K. Shen
 
M

MRAB

I ran the following code:

def xx(nlist):
print("begin: ",nlist)
nlist+=[999]
print("middle:",nlist)
nlist=nlist[:-1]
print("final: ",nlist)

u=[1,2,3,4]
print(u)
xx(u)
print(u)

and obtained the following result:

[1, 2, 3, 4]
begin: [1, 2, 3, 4]
middle: [1, 2, 3, 4, 999]
final: [1, 2, 3, 4]
[1, 2, 3, 4, 999]

As beginner I couldn't understand why the last line wasn't [1, 2, 3, 4].
Could someone kindly help?
This:

nlist+=[999]

appends to the list, making it [1, 2, 3, 4, 999].

This:

nlist=nlist[:-1]

gets a slice of the list and then binds it to the local name 'nlist'.
 
M

Madison May

I ran the following code:



def xx(nlist):

print("begin: ",nlist)

nlist+=[999]

print("middle:",nlist)

nlist=nlist[:-1]

print("final: ",nlist)



u=[1,2,3,4]

print(u)

xx(u)

print(u)



and obtained the following result:



[1, 2, 3, 4]

begin: [1, 2, 3, 4]

middle: [1, 2, 3, 4, 999]

final: [1, 2, 3, 4]

[1, 2, 3, 4, 999]



As beginner I couldn't understand why the last line wasn't [1, 2, 3, 4].

Could someone kindly help?



M. K. Shen

The list nlist inside of function xx is not the same as the variable u outside of the function: nlist and u refer to two separate list objects. Whenyou modify nlist, you are not modifying u. If you wanted the last line tobe [1, 2, 3, 4], you could use the code below:

#BEGIN CODE

def xx(nlist):

print("begin: ",nlist)

nlist+=[999]

print("middle:",nlist)

nlist=nlist[:-1]

print("final: ",nlist)

return nlist

u=[1,2,3,4]

print(u)

u = xx(u)

print(u)

#END CODE


Notice that I changed two things. First, the function xx(nlist) returns nlist. Secondly, u is reassigned to the result of xx(nlist).
 
M

Madison May

I ran the following code:



def xx(nlist):

print("begin: ",nlist)

nlist+=[999]

print("middle:",nlist)

nlist=nlist[:-1]

print("final: ",nlist)



u=[1,2,3,4]

print(u)

xx(u)

print(u)



and obtained the following result:



[1, 2, 3, 4]

begin: [1, 2, 3, 4]

middle: [1, 2, 3, 4, 999]

final: [1, 2, 3, 4]

[1, 2, 3, 4, 999]



As beginner I couldn't understand why the last line wasn't [1, 2, 3, 4].

Could someone kindly help?



M. K. Shen

I've modified your code slightly so you can see what's happening with u in the middle of function xx. Take a look:

u=[1,2,3,4]

def xx(nlist):
print("xx(u)\n")
print("At first, u and nlist refer to the same list")
print("nlist: %s u: %s\n" % (nlist, u))

nlist+=[999]

print("nlist+=[999]\n")
print("The list has been modified in place. u and nlist are still equal")
print("nlist: %s u: %s\n" %(nlist, u))

nlist=nlist[:-1]

print("nlist=nlist[:1]\n")
print("Now nlist refers to a new list object in memory that was created by")
print("taking a slice of u. u and nlist are no longer equal.")
print("nlist: %s u: %s" %(nlist, u))

xx(u)

Here's the output:


xx(u)

At first, u and nlist refer to the same list
nlist: [1, 2, 3, 4] u: [1, 2, 3, 4]

nlist+=[999]

The list has been modified in place. u and nlist are still equal
nlist: [1, 2, 3, 4, 999] u: [1, 2, 3, 4, 999]

nlist=nlist[:1]

Now nlist refers to a new list object in memory that was created by
taking a slice of u. u and nlist are no longer equal.
nlist: [1, 2, 3, 4] u: [1, 2, 3, 4, 999]


Thank you, Rob Day, for explaining a some of what's happening behind the scenes.
 
T

Terry Reedy

Madison May wrote:
The list nlist inside of function xx is not the same as the variable
u outside of the function: nlist and u refer to two separate list
objects. When you modify nlist, you are not modifying u.
<http://mail.python.org/mailman/listinfo/python-list>

This is confused and wrong. The parameter *name* 'nlist' of function xx
is not the same as the *name* 'u' outside the function. The call xx(u)
binds nlist to the same object that u is bound to. At that point, the
two name *are* bound to the same list object. The statement
"nlist+=[999]" dodifying nlist *does* modify u. The subsequent
assignment statement "nlist=nlist[:-1]" rebinds 'nlist' to a *new* list
object. That new object gets deleted when the function returns. So the
rebinding is completely useless.

This sequence, modifying the input argument and then rebinding to a new
object, is bad code.
Well - that's not quite true. Before calling the function, u is [1, 2,
3, 4] - but after calling the function, u is [1, 2, 3, 4, 999]. This is
a result of using 'nlist += [999]' - the same thing doesn't happen if
you use 'nlist = nlist+[999]' instead.

I'm not completely aware of what's going on behind the scenes here, but

you got it right.
I think the problem is that 'nlist' is actually a reference to a list
object - it points to the same place as u.

Calling a python function binds parameter names to argument objects or
(for *args and **kwds parameters) a collection based on argument objects.
When you assign to it within
the function, then it becomes separate from u - which is why nlist =
nlist+[999] and nlist = nlist[:-1] don't modify u - but if you modify
nlist in place before doing that, such as by using +=, then it's still
pointing to u, and so u gets modified as well.
 
M

Madison May

On 8/15/2012 5:58 PM, Rob Day wrote:

Yeah, my apologies for any confusion I created. Although I suppose my explanation would be somewhat true for immutable objects since they can't be modified in-place (any modification at all would cause the creation of a new immutable object right?), I now understand that it is completely and totally wrong for mutable objects.

Thanks for the in-depth explanations, Terry and Rob. I feel like I have a much more solid grasp of what's going on behind the scenes after your analysis.
Madison May wrote:
The list nlist inside of function xx is not the same as the variable
u outside of the function: nlist and u refer to two separate list
objects. When you modify nlist, you are not modifying u.



This is confused and wrong. The parameter *name* 'nlist' of function xx

is not the same as the *name* 'u' outside the function. The call xx(u)

binds nlist to the same object that u is bound to. At that point, the

two name *are* bound to the same list object. The statement

"nlist+=[999]" dodifying nlist *does* modify u. The subsequent

assignment statement "nlist=nlist[:-1]" rebinds 'nlist' to a *new* list

object. That new object gets deleted when the function returns. So the

rebinding is completely useless.



This sequence, modifying the input argument and then rebinding to a new

object, is bad code.


Well - that's not quite true. Before calling the function, u is [1, 2,
3, 4] - but after calling the function, u is [1, 2, 3, 4, 999]. This is
a result of using 'nlist += [999]' - the same thing doesn't happen if
you use 'nlist = nlist+[999]' instead.
I'm not completely aware of what's going on behind the scenes here, but



you got it right.


I think the problem is that 'nlist' is actually a reference to a list
object - it points to the same place as u.



Calling a python function binds parameter names to argument objects or

(for *args and **kwds parameters) a collection based on argument objects.


When you assign to it within
the function, then it becomes separate from u - which is why nlist =
nlist+[999] and nlist = nlist[:-1] don't modify u - but if you modify
nlist in place before doing that, such as by using +=, then it's still
pointing to u, and so u gets modified as well.
 
C

Cheng

I ran the following code:



def xx(nlist):

print("begin: ",nlist)

nlist+=[999]

print("middle:",nlist)

nlist=nlist[:-1]

print("final: ",nlist)



u=[1,2,3,4]

print(u)

xx(u)

print(u)



and obtained the following result:



[1, 2, 3, 4]

begin: [1, 2, 3, 4]

middle: [1, 2, 3, 4, 999]

final: [1, 2, 3, 4]

[1, 2, 3, 4, 999]



As beginner I couldn't understand why the last line wasn't [1, 2, 3, 4].

Could someone kindly help?



M. K. Shen

When you pass a list (mutable object) to a function, the pointer to the list is passed to the function and the corresponding argument points to the same memory location as the pointer passed in. So in this case, nlist points to the same memory location which u points to when xx is called, i.e. nlist and u points to same memory location which contains [1,2,3,4].

nlist += [999] is equivalent to nlist.extend([999]). This statement addsthe argument list to the original list, i.e. the memory location pointed by nlist and u now contains [1,2,3,4,999]. So, print(u) after calling xx will print [1,2,3,4,999].

nlist += [999] is not the same as nlist = nlist + [999]. In the later case, nlist + [999] will create a new memory location containing the two lists combined and rebind nlist to the new location, i.e. nlist points to a new memory location that has [1,2,3,4,999]. So if nlist = nlist +[999] isused, the original memory location containing [1,2,3,4] is untouched, and print(u) after calling xx will print [1,2,3,4]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top