python:confusion about assignment statement:l = [a,b] = [0,1]? - python

In python 3.4 interactive prompt:
>>> l = [a,b] = [0,1]
>>> a is l[0]
True
>>> b is l[1]
True
>>> l[0] = 2
>>> a
0
>>> l
[2, 1]
I assume that the following statement performs in place change of the first element of the list.
l[0] = 2
Since the variable a is referencing the same object,why it's value remains 0? What happens internally in this assignment statement?

This is because you actually create three variables there a, b, and l. Only the last one is a list. What happened in line-by-line format was this:
a = 0
b = 1
l = [a, b] #which means l = [0, 1], not really the same referencing element a, b
Then if you check
a is l[0]
b is l[1]
Both return true because the value they have are the same, but again, the values, not the references
Then when you change:
l[0] = 2
Only value in l[0] changes, it does not affect a. Best is to check using good debugger tool like PyCharm. It shows you in the watch windows and inlines all the current values of the variables.

a and l[0] are two names for the same object, but when you say l[0] = 2, you are just redefining l[0]. a still refers to the same object as it did before; it's just l[0] that has changed. a refers to an object, not a position.

I think the confusion is due to the initial assignment:
l = [a,b] = [0,1]
This is equivalent to:
t = [0, 1]
l = [a, b] = t
which in turn is equivalent to:
t = [0, 1]
a = t[0]
b = t[1]
l = t
which in turn is equivalent to:
l = [0, 1]
a = l[0]
b = l[1]
The rest follows from this.

Related

python, how to make/change a list with lists

So more or less i am trying to figure this out:
a = [1,2]
b = [3,4,5]
c = [6,7,8,9]
z = [a,b,c]
def raiseInt():
x = 0
for int in z:
a[x] + 1
b[x] + 1
c[x] + 1
I'm trying to increase every int in every list by 1
I will try to make my code self-explanatory. Note the name of each object
a = [1,2]
b = [3,4,5]
c = [6,7,8,9]
z = [a,b,c]
def raiseInt(list_to_increase_by_1):
#x = 0 we may actually do not need to assign this variable.
for sublist in list_to_increase_by_1:
for index_of_element, element in enumerate(sublist):
sublist[index_of_element] += 1
return list_to_increase_by_1
print raiseInt(z)
best practice related details
As you can see from Moinuddin Quadri's comments, I do not use the variable (iteratively assigned) element. In this case, the convention is about naming it _, so as to explicit that tha variable is actually not used.Which thus turns the code into
def raiseInt(list_to_increase_by_1):
for sublist in list_to_increase_by_1:
for index_of_element, _ in enumerate(sublist):
sublist[index_of_element] += 1
return list_to_increase_by_1
more best practice related details
As can be read from Paul Ronney's comment
[strictly doing as above] is contrary to python best practice, that any in place modifying function returns None. It should do one or the other and if the choice is to return it should return a copy and leave the original intact
Thus, folowing this comment implies to define raiseInt as an in place modifying function, as follows
def raiseInt(list_to_increase_by_1):
for sublist in list_to_increase_by_1:
for index_of_element, _ in enumerate(sublist):
sublist[index_of_element] += 1
I.e. with the function returning None
A very simple way to do this
a = [1,2]
b = [3,4,5]
c = [6,7,8,9]
z = [a,b,c]
def raiseInt():
for L in z:
for i in range(len(L)):
L[i] +=1
print(z)
raiseInt()
print(z)
output
[[1, 2], [3, 4, 5], [6, 7, 8, 9]]
[[2, 3], [4, 5, 6], [7, 8, 9, 10]]
Iterate over the lists in z and then iterate for a number of times equal to the lists length and increment each element.
You could certainly improve your function by passing the lists to be operated on in as a parameter. This would make your function more generally useful, as it is, it can only operate on that one list called z.
def raiseInt():
for v in z:
for i in range(len(v)):
v[i] += 1;

Is there any way to use python list as reference of original object even with "=" sign?

I hope to achieve the following function with list:
a = 1
b = 2
c = 3
l = []
l.append(a)
l.append(b)
l.append(c)
and if I do:
l[0] = 4
I hope I could get
l = [4, 2, 3]
as well as
a = 4
The difference between this question and many other similar questions is that, I hope to find a way to achieve this with = sign, which in most cases will mean to ask the list set its pointer to another object instead of giving the right hand side value to its current pointing one.
You can't. a=4 points to the integer value 4, which is immutable in python. You cannot change it. You can only change the value of mutable objects, like lists, sets, and dictionaries, plus custom made objects.
You can only do something like:
>>> a = [1]
>>> b = [2]
>>> c = [3]
>>> l = []
>>> l.append(a)
>>> l.append(b)
>>> l.append(c)
>>> l
[[1], [2], [3]]
>>> l[0][0] = 4
>>> a
[4]
>>> l
[[4], [2], [3]]
>>>
Since l[0] = 4 will create a new object, not change a.

Why do I need to copy class instances but not other object types in Python?

I'm a little confused about when I need to explicitly copy an object in Python in order to make changes without altering the original. The Python doc page doesn't have too much detail, and simply says that "assignment statements do not create copies".
Example 1:
>>> a = 4
>>> b = a
>>> b += 1
>>> print(b)
>>> print(a)
# Results are what you'd "expect" them to be:
5
4
Example 2:
>>> class Test():
>>> def __init__(self, x):
>>> self.x = x
>>>
>>> A = Test(4)
>>> B = A
>>> B.x += 1
>>> print(B.x)
>>> print(A.x)
# Unexpected results because B isn't actually a copy of A:
5
5
Why do the two examples behave differently?
Edit: In order to get Example 2 to work, I basically did the following. I'm asking why this isn't necessary for Example 1:
>>> import copy
>>> A = Test(4)
>>> B = copy.copy(A)
>>> B.x += 1
>>> print(B.x)
>>> print(A.x)
a = 4
b = a
..would mean "make b refer to whatever a refers to". That would be 4 in this case. Since integers are immutable, changing b by doing b += 1 would make it point to a different object
Check their ids:
a = 4
b = a
print(id(a)) # Same id
print(id(b)) # Same id
b = 123
print(id(b)) # Different id
Same thing happens with instances A and B when B is not a .copy().
id(object)
Return the “identity” of an object.
An interesting example with mutable objects:
l = [1, 2]
k = l
print(id(l)) # Same id
print(id(k)) # Same id
k.append(3)
print(id(k)) # Same id
print(l, k) # Prints [1, 2, 3] [1, 2, 3]
append() modifies the object both k and l refer to. It doesn't assign k to a different object.
As mentioned by #blcckngth:
k = k + [3]
print(id(k)) # Different id ..
print(l, k) # ..prints [1, 2] [1, 2, 3]
while k += [3] would result in reference to the same object.
In your example 1, you write b += 1. That's the same thing as writing b = b + 1. That uses the = operator to assign a value to b. You're just changing the value that the name b refers to. In example 2, you're changing an attribute of the object that both names (A and B) refer to. They still both refer to the same object in memory, so changing the .x attribute of that object changes both B.x and A.x.

List B append in list A - but when B removed A also empty

I just realized now that when I append a list to another list and I delete this appended list, the list also wont be in the other list.
Makes maybe sense, because appending a list to somewhere else is just a reference. So when I'm using something like this:
B[:] = []
Then it will be gone from everywhere. How can I avoid this issue? Using copy? My problem is that I'm collecting lists in a list and at some point I'm adding this whole thing to another list - after that I would like to make the added list empty to use it to adding new data to it.
I think easiet way will be:
>>> a = []
>>> b = ['k']
>>> a.append(list(b))
>>> b[:] = []
>>> b
11: []
>>> a
12: [['k']]
>>> a = [1, 2, 3, 4]
>>> b = list()
>>> b.append(a[:])
>>> a = []
>>> b
[[1, 2, 3, 4]]
You need to copy the List in another object and should operate then:-
a, b = range(10), []
c = a[:]
b.append(c)
a[:] = []

How to re-assign items in a list in Python?

I want to re-assign each item in a list in Python.
In [20]: l = [1,2,3,4,5]
In [21]: for i in l:
....: i = i + 1
....:
....:
But the list didn't change at all.
In [22]: l
Out[22]: [1, 2, 3, 4, 5]
I want to know why this happened. Could any body explain the list iterating in detail? Thanks.
You can't do it like that, you are merely changing the value binded to the name i. On each iteration of the for loop, i is binded to a value in the list. It is not a pointer in the sense that by changing the value of i you are changing a value in the list. Instead, as I said before, it is simply a name and you are just changing the value that name refers to. In this case, i = i + 1, binds i to the value i + 1. So you aren't actually affecting the list itself, to do that you have to set it by index.
>>> L = [1,2,3,4,5]
>>> for i in range(len(L)):
L[i] = L[i] + 1
>>> L
[2, 3, 4, 5, 6]
Some pythonistas may prefer to iterate like this:
for i, n in enumerate(L): # where i is the index, n is each number
L[i] = n + 1
However you can easily achieve the same result with a list comprehension:
>>> L = [1,2,3,4,5]
>>> L = [n + 1 for n in L]
>>> L
[2, 3, 4, 5, 6]
For more info: http://www.effbot.org/zone/python-objects.htm
This is because of how Python handles variables and the values they reference.
You should modify the list element itself:
for i in xrange(len(l)):
l[i] += 1
>>> a = [1, 2, 3, 4, 5]
>>> a = [i + 1 for i in a]
>>> a
[2, 3, 4, 5, 6]
Initially i is a pointer to the item inside the list, but when you reassign it, it will point to the new number, that is why the list will not be changed.
For a list of mutable objects it would work:
class Number(object):
def __init__(self,n):
self.n=n
def increment(self):
self.n+=1
def __repr__(self):
return 'Number(%d)' % self.n
a = [Number(i) for i in xrange(5)]
print a
for i in a:
i.increment()
print a
But int are not mutable, when you do an operation on them you get a new int object, and that is why it doesn't work in your case.

Categories