Example one: Changing the value that has been appended to b changes the value in the original list l
>>> l = [1 , 2, 3]
>>> b = []
>>> b.append(l)
>>> b[0].append(4)
>>> b
[[1, 2, 3, 4]]
>>> l
[1, 2, 3, 4]
Example 2: l1 is appended to ans and then the value of l1 is modified. However, the value in ans remains the same.
>>> l1 = [1, 2, 3]
>>> ans = []
>>> ans.append(l1)
>>> ans
[[1, 2, 3]]
>>> l1 = [2, 3, 4]
>>> ans
[[1, 2, 3]]
I seem to be missing some fundamental point about the mutability of lists. Could someone please point it out?
You are not mutating l1. You are assigning a new object to the same name, which makes that name point to a new object. You are moving a label, not modifying an object. The only remaining reference to the list that l1 used to point to is now ans[0].
In your first example, l is a pointer, as well as b.
l is then appended to b, so b[0] now refers to the pointer.
Next, you append 4 to b[0], which is the same thing as l, so 4 is added to both b[0] and l.
In your second example, ans contains the pointer of l1, just like b contained the pointer of l
Then, you changed l1 itself by assigning it to a different array, so l1 changed but ans[0] did not.
The biggest takeaway from this is that append just changes the list, and the pointer remains the same. But when you set a variable to a different list, the pointer changes.
Replace
>>> l1 = [2, 3, 4]
with
>>> l1[:] = [2, 3, 4]
That will not assign a new list to l1.
Related
Consider:
a = [1, 2, 3]
When I slice it I get a new list b:
b = a[:2]
If I now alter list b:
b[0] = 0
I get a = [1, 2, 3] and b = [0, 2]. Why doesn't the a list get altered as well? I know that slicing creates a new list object, but why is it not the object of the same elements as the inital object? How can I slice a so that:
a = [1, 2, 3]
b = a[:2]
b[0] = 0
Results in a = [0, 2, 3] and b = [0, 2].
You could try slicing later:
a = [1, 2, 3]
b = a
b[0] = 0
b = b[:2]
print(a, b)
Output:
[0, 2, 3] [0, 2]
The notation [:2] is making a shallow copy of the list a upto the 3rd index.
For instance, if you would have ever seen programmers doing [:] while iterating over a list, they are creating the shallow copy of the list. Similarly, the above notation makes a copy of the list upto the 3rd index so you get something as:
[1, 2]
To get the result, you can do:
a = [1, 2, 3]
b = a
b[0] =0
In here b = a is not making a copy the list. Both a, b point to the same list in the memory.
If you change either of the 2, it will reflect in both of them. Later, you can slice b by [:2]
Following can be used to add a slice to append to front of list.
>>> a = [5,6]
>>> a[0:0] = [1,2,3]
>>> a
[1,2,3,5,6]
what slice to use to append to the end of list.
If you really want to use slice, you can use the length of a:
a = [5, 6]
a[len(a):] = [1, 2, 3]
a
output:
[5, 6, 1, 2, 3]
But the simplest is to directly extend a:
a = [5, 6]
a += [1, 2, 3] # or a.extend([1, 2, 3])
I think you should consider extend():
>>> a = [1, 2, 3]
>>> a.extend([4, 5, 6])
>>> a
[1, 2, 3, 4, 5, 6]
Both + and += operators are defined for list, which are semantically
similar to extend.
list + list2 creates a third list in memory, so you can return the
result of it, but it requires that the second iterable be a list.
list += list2 modifies the list in-place (it is the in-place operator,
and lists are mutable objects, as we've seen) so it does not create a
new list. It also works like extend, in that the second iterable can
be any kind of iterable.
Time Complexity
Append has constant time complexity, O(1).
Extend has time complexity, O(k).
Iterating through the multiple calls to append adds to the complexity,
making it equivalent to that of extend, and since extend's iteration
is implemented in C, it will always be faster if you intend to append
successive items from an iterable onto a list.
↳ More Information
>>> a = [1, 2, 3]
>>> a[len(a):] = [4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
or
>>> a = [1, 2, 3]
>>> a += [4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
You have got short answer from Jeevaa and Reblochon Masque but if you want to use for loop then try this:
a = [5,6]
b = [1,2,3]
for val in b[::-1]:#Reverse b and insert it to a
a.insert(0,val)
print(a)
Output
[1,2,3,5,6]
I would like to know if there is a possibility of copying an entire list on an element of another one.
a = [1, 2, 3]
b = []
b[0] = list(a)
print(b)
It gives the error: list assignment index out of range
But if we do not copy it and we only put it there:
a = [1, 2, 3]
b = [a]
print(b)
It works and prints: [[1, 2, 3]]
Can this be done?
It gives the error: "list assignment index out of range"
Because you have created b as an empty list with b=[] and then you try and access the first element [0] of list b with b[0] when executing b[0] = list(a), and that index doesn't exist for an empty list.
To add a value to a list, you generally always use the list.append() method:
a = [1, 2, 3]
b = []
b.append(a) # similar to b = [a] but more intuitive.
print(b) # prints b = [[1, 2, 3]]
Simple, clear and concise.
A Note of caution:
b.append(a) and b.append(list(a)) are two similarly looking different things.
b.append(a) (similar to b = [a]) copies a reference of a in b while b.append(list(a)) creates a new list from the values of a and adds it to the list b. Because lists are mutable, this has comfusing implications when manipulating the internal list.
This becomes clearer with an example, where a = [1, 2, 3] and b=[] in each example:
With b.append(a):
b.append(a)
print(b) # prints b = [[1, 2, 3]]
# Now if we modify a:
a.append(4) # a = [1, 2, 3, 4]
# Changes are visible in b:
print(b) # b = [[1, 2, 3, 4]]
With b.append(list(a)):
b.append(list(a))
print(b) # prints b = [[1, 2, 3]]
# Now if we modify a:
a.append(4) # a = [1, 2, 3, 4]
# Changes are NOT visible in b:
print(b) # b = [[1, 2, 3]]
Python lists do not allow you to modify elements with an index equal to or greater than the length of the list. The first element of an empty list does not exist. You need to add it with b.append(list(a))
l = [1, 2]
l.append(l)
>>>l
[1, 2, [...]] #l is an infinite list
Why does this create an infinite list instead of creating:
l = [1, 2]
l.append(l)
>>>l
[1, 2, [1, 2]]
When you do:
l.append(l)
a reference to list l is appended to list l:
>>> l = [1, 2]
>>> l.append(l)
>>> l is l[2]
True
>>>
In other words, you put the list inside itself. This creates an infinite reference cycle which is represented by [...].
To do what you want, you need to append a copy of list l:
>>> l = [1, 2]
>>> l.append(l[:]) # Could also do 'l.append(list(l))' or 'l.append(l.copy())'
>>> l
[1, 2, [1, 2]]
>>> l is l[2]
False
>>>
Easy, because each object will have a reference to itself in the third element. To achieve [1, 2, [1, 2]] then use a copy of the list.
l.append(l[:])
This question already has answers here:
Confusing [...] List in Python: What is it?
(9 answers)
Closed 9 years ago.
I just seen a output like below - just want to know what is happening here.
>>> l = [1,2,3,4]
>>> l[0]=l
>>> l
[[...], 2, 3, 4]
Why the l[0] value has displayed like this? Can anyone explain me why this behavior.
I was thinking it'd return like, [[1,2,3,4], 2, 3, 4].
Cheers,
Kalai
It shows the ... because otherwise it would have to infinitely recurse.
A list object in Python is a pointer to a list- assigning it like l[0] = l doesn't make a copy. For instance, try
l1 = [1, 2, 3, 4]
l2 = [1, 2]
l2[0] = l1
print l2
# [[1, 2, 3, 4], 2]
l2[0].append(5)
print l1
# [1, 2, 3, 4, 5]
Notice that even though you never changed l1 explicitly, it has now been appended to.
Therefore, when you place a list within itself, that item of the list is still a link to the entire list. After your code above, try doing:
l[1] # ==> 2
l[0][1] # ==> 2
l[0][0][1] # ==> 2
Use a copy of the list to avoid infinite recursion:
In [10]: l = [1,2,3,4]
In [11]: l[0] = l[:]
In [12]: l
Out[12]: [[1, 2, 3, 4], 2, 3, 4]
If you would have used a PrettyPrinter, the output would had been self explanatory
>>> l = [1,2,3,4]
>>> l[0]=l
>>> l
[[...], 2, 3, 4]
>>> pp = pprint.PrettyPrinter(indent = 4)
>>> pp.pprint(l)
[<Recursion on list with id=70327632>, 2, 3, 4]
>>> id(l)
70327632