Python: Extending the result from the built-in list() function - python

I have an original list whose contents are determined in another function, and I wish to add the numbers 0 and 5 to the list to make an extended list, without corrupting the original. In this application, I know that 0 and 5 will never be part of the original list, so I am not concerned with duplication. And I am not concerned with the order or the elements either.
For reasons discussed in another question, the following does not work because it corrupts the original list:
>>> orig = [1,6]
>>> extended = orig
>>> extended.extend([0,5])
>>> extended
[1, 6, 0, 5]
>>> orig
[1, 6, 0, 5]
One of the solutions proposed is to use the built-in list() function. This produces the desired result:
>>> orig = [1,6]
>>> extended = list(orig)
>>> extended.extend([0,5])
>>> extended
[1, 6, 0, 5]
>>> orig
[1, 6]
Then I attempted to combine the 2nd and 3rd lines of 2. This produces a 'None' result, and only if you print it.
>>> orig = [1,6]
>>> extended = list(orig).extend([0,5])
>>> extended
>>> print extended
None
What I eventually coded, which is neater than any of the previous attempts, is this, using concatenation.
>>> orig = [1,6]
>>> extended = orig + [0,5]
>>> extended
[1, 6, 0, 5]
>>> orig
[1, 6]
But my question is, why won't example 3 work? It looks reasonable (to me), and it doesn't return an error. It just produces 'None'.
I am using Python 2.7.8.

extend is an inplace operation, like list.sort, list.append it affects the original list. All those methods because they don't return any value return None so you are simply seeing the return value of extend when you extended = list(orig).extend([0,5]).
In [6]: l = [1,2,3]
In [7]: e = l.extend([4,5])
In [8]: print e
None
In [9]: l = [1,2,3]
In [10]: a = l.append(6)
In [11]: print a
None

Related

Appending to a list comprehension in Python returns None

This is a question out of curiosity rather than trying to use it for a practical purpose.
Consider I have the following simple example where I generate a list through list comprehension:
>>> a = [1, 2, 3]
>>> b = [2 * i for i in a]
>>> b
[2, 4, 6]
>>> b.append(a)
>>> b
[2, 4, 6, [1, 2, 3]]
However if I try and do this all in one action
>>> a = [1, 2, 3]
>>> b = [2 * i for i in a].append(a)
>>> b == None
True
The result returns None. Is there any reason why this is the case?
I would have thought that an action like this would either return an answer like in the first example or throw an error.
For reference I'm using Python 3.6.5
append only works on variables, not list literals, since it updates the list object itself and does not return the resulting list.
As #Tomalak mentioned noted, running a similar operation on a simple list also returns None
>>> [1, 2, 3].append(4) == None
True
You can use concatination + instead of append in list comprehension
In [1]: a = [1, 2, 3]
In [2]: b = [2 * i for i in a] + [a]
In [3]: b
Out[3]: [2, 4, 6, [1, 2, 3]]
#ScottMcC, methods defined on mutable objects like list, dictionary mostly perform operations on calling object and doesn't return anything.
In case of immutable object like string you may see, methods return the modified form(a different object) of the calling object. In case of list, it's different.
You can't expect the below operations on list kind of mutable objects.
s = "hello DJANGO"
s2 = s.upper()
s3 = s.lower()
print(s) # hello DJANGO
print(s2) # HELLO DJANGO
print(s3) # hello django
Now, have a look at the below examples.
list is mutable object.
Calling sort() method on list directly modified the calling object and doesn't return anything (That's why None).
Calling sorted() function doesn't alter the passing list. It creates a separate sorted list based on the passed list. As it is not a method defined on list object, it returns the new sorted list.
append() method appends item on the calling list and doesn't return anything. Once you call it, you are done with updating (appending an item) the list.
# sort() method defined on list updates the calling list
# As it updates current list, it doesn't return anything. That's why None.
a = [5, 8, 1, 2, 7]
n = a.sort()
print (a)
print(n)
print ()
# sorted() function returns a new sorted list
# It doesn't update the calling list a2
a2 = [5, 8, 1, 2, 7];
n = sorted(a2);
print (a2)
print(n)
print()
# append() is method defined on list, it updates calling list so it doesn't return anything (None)
l = []
n = l.append(34)
print(l)
print (n)
Output
[1, 2, 5, 7, 8]
None
[5, 8, 1, 2, 7]
[1, 2, 5, 7, 8]
[34]
None

python list comprehension and extend() [duplicate]

This question already has answers here:
Why do these list operations (methods: clear / extend / reverse / append / sort / remove) return None, rather than the resulting list?
(6 answers)
Closed 5 months ago.
Working my way into Python (2.7.1)
But failing to make sense (for hours) of this:
>>> a = [1, 2]
>>> b = [3, 4]
>>>
>>> a.extend([b[0]])
>>> a
[1, 2, 3]
>>>
>>> a.extend([b[1]])
>>> a
[1, 2, 3, 4]
>>>
>>> m = [a.extend([b[i]]) for i in range(len(b))] # list of lists
>>> m
[None, None]
The first two extends work as expected, but when compacting the same in a list comprehension it fails.
What am i doing wrong?
extend modifies the list in-place.
>>> [a + b[0:i] for i in range(len(b)+1)]
[[1, 2], [1, 2, 3], [1, 2, 3, 4]]
list.extend() extends a list in place. Python standard library methods that alter objects in-place always return None (the default); your list comprehension executed a.extend() twice and thus the resulting list consists of two None return values.
Your a.extend() calls otherwise worked just fine; if you were to print a it would show:
[1, 2, 3, 4, 3, 4]
You don't see the None return value in the Python interpreter, because the interpreter never echoes None results. You could test for that explicitly:
>>> a = []
>>> a.extend(['foo', 'bar']) is None
True
>>> a
['foo', 'bar']
the return value of extend is None.
extend function extends the list with the value you've provided in-place and returns None. That's why you have two None values in your list. I propose you rewrite your comprehension like so:
a = [1, 2]
b = [3, 4]
m = [a + [v] for v in b] # m is [[1,2,3],[1,2,4]]
For python lists, methods that change the list work in place and return None. This applies to extendas well as to append, remove, insert, ...
In reply to an older question, I sketched an subclass of list that would behave as you expected list to work.
Why does [].append() not work in python?
This is intended as educational. For pros and cons.. look at the comments to my answer.
I like this for the ability of chaining methods and working in a fluent style, e.g. then something like
li = FluentList()
li.extend([1,4,6]).remove(4).append(7).insert(1,10).reverse().sort(key=lambda x:x%2)
would be possible.
a.extend() returns None.
You probably want one of these:
>>> m = a + b
>>> m
[1, 2, 3, 4]
>>> a.extend(b)
>>> a
[1, 2, 3, 4]
Aside from that, if you want to iterate over all elements of a list, you just can do it like that:
m = [somefunction(element) for element in somelist]
or
for element in somelist:
do_some_thing(element)
In most cases there is no need to go over the indices.
And if you want to add just one element to a list, you should use somelist.append(element) instead of `somelist.extend([element])

Python appending two returns to two different lists

I am wanting to append two returned lists to two different lists such as
def func():
return [1, 2, 3], [4, 5, 6]
list1.append(), list2.append() = func()
Any ideas?
You'll have to capture the return values first, then append:
res1, res2 = func()
list1.append(res1)
list2.append(res2)
You appear to be returning lists here, are you certain you don't mean to use list.extend() instead?
If you were extending list1 and list2, you could use slice assignments:
list1[len(list1):], list2[len(list2):] = func()
but this is a) surprising to newcomers and b) rather unreadable in my opinion. I'd still use the separate assignment, then extend calls:
res1, res2 = func()
list1.extend(res1)
list2.extend(res2)
Why not just storing the return values?
a, b = func() #Here we store it in a and b
list1.append(a) #append the first result to a
list2.append(b) #append the second one to b
With this, if a was previously [10] and b was previously [20], you'll have this result:
>>> a, b
[10, [1,2,3]], [20,[4,5,6]]
Nah, that wasn't difficult, was it?
By the way, you probably want to merge the lists. For this, you can use extend:
list1.extend(a)
Hope it helps!
A one line solution isn't possible (unless you use some cryptic hack, which is always a bad idea).
The best you can get is:
>>> list1 = []
>>> list2 = []
>>> def func():
... return [1, 2, 3], [4, 5, 6]
...
>>> a,b = func() # Get the return values
>>> list1.append(a) # Append the first
>>> list2.append(b) # Append the second
>>> list1
[[1, 2, 3]]
>>> list2
[[4, 5, 6]]
>>>
It's readable and efficient.

Can I extend list in Python with prepend elements instead of append?

I can perform
a = [1,2,3]
b = [4,5,6]
a.extend(b)
# a is now [1,2,3,4,5,6]
Is there way to perform an action for extending list and adding new items to the beginning of the list?
Like this
a = [1,2,3]
b = [4,5,6]
a.someaction(b)
# a is now [4,5,6,1,2,3]
I use version 2.7.5, if it is important.
You can assign to a slice:
a[:0] = b
Demo:
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a[:0] = b
>>> a
[4, 5, 6, 1, 2, 3]
Essentially, list.extend() is an assignment to the list[len(list):] slice.
You can 'insert' another list at any position, just address the empty slice at that location:
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a[1:1] = b
>>> a
[1, 4, 5, 6, 2, 3]
This is what you need ;-)
a = b + a
You could use collections.deque:
import collections
a = collections.deque([1, 2, 3])
b = [4, 5, 6]
a.extendleft(b[::-1])
If you need fast operations and you need to be able to access arbitrary elements, try a treap or red-black tree.
>>> import treap as treap_mod
>>> treap = treap_mod.treap()
>>> for i in range(100000):
... treap[i] = i
...
>>> treap[treap.find_min() - 1] = -1
>>> treap[100]
100
Most operations on treaps and red-black trees can be done in O(log(n)). Treaps are purportedly faster on average, but red-black trees give a lower variance in operation times.

Assigning a value to an element of a slice in Python

This is a simple question about how Python handles data and variables. I've done a lot of experimenting and have Python mostly figured out, except this keeps tripping me up:
[edit: I separated and rearranged the examples for clarity]
Example 1:
>>> a = [[1], 2]
>>> a[0:1]
[[1]]
>>> a[0:1] = [[5]]
>>> a
[[5], 2] # The assignment worked.
Example 2:
>>> a = [[1], 2]
>>> a[0:1][0]
[1]
>>> a[0:1][0] = [5]
>>> a
[[1], 2] # No change?
Example 3:
>>> a = [[1], 2]
>>> a[0:1][0][0]
1
>>> a[0:1][0][0] = 5
>>> a
[[5], 2] # Why now?
Can anybody explain to me what's going on here?
So far the answers seem to claim that a[0:1] returns a new list containing a reference to the first element of a. But I don't see how that explains Example 1.
a[0:1] is returning a new array which contains a reference to the array [1], thus you end up modifying the inner array via a reference call.
The reason the first case doesn't modify the [1] array is that you're assigning the copied outer array a new inner array value.
Bottom line - a[0:1] returns a copy of the data, but the inner data is not copied.
My understanding is slicing returns a new object. That is it's return value is a new list.
Hence you can not use an assignment operator to changes the values of the original list
>>> a = [[1], 2, 3]
>>> k = a[0:2]
>>> id(a)
4299352904
>>> id(k)
4299353552
>>>
>>> id(a)
4299352904
>>> id(a[0:2])
4299352832
some more plays along the lines
>>> k = 5
>>>
>>> id(k)
4298182344
>>> a[0] = [1,2]
>>> a
[[1, 2], 2, 3]
>>> id(a)
4299352904
>>>
[Edit: on second part of question]
>>> a[0:1] = [[5]]
The following notation is also called commonly as slice assignment
The behavior for builtin lists is atomic (delete + insert) happens in one go. My understanding is that this is not allowed for custom sequence.
There are three distinct operations with indices, all are translated to method calls:
a[i] = b => a.__setitem__(i, b)
del a[i] => a.__delitem__(i)
a[i] used as an expression => a.__getitem__(i)
Here a, b and i are expressions, and i can contain slice objects created using the colon shorthand syntax. E.g.:
>>> class C(object):
... def __setitem__(self, *a):
... print a
...
>>> C()[1] = 0
(1, 0)
>>> C()['foo'] = 0
('foo', 0)
>>> C()['foo':'bar'] = 0
(slice('foo', 'bar', None), 0)
>>> C()['foo':'bar',5] = 0
((slice('foo', 'bar', None), 5), 0)
So what's happening in your third example is this:
a[0:1][0][0] = 5
becomes
a.__getitem__(slice(0,1)).__getitem__(0).__setitem__(0, 5)
The first __getitem__ returns a copy of part of the list, but the second __getitem__ returns the actual list inside that, which is then modified using __setitem__.
Your second example on the other hand becomes
a.__getitem__(slice(0,1)).__setitem__(0, 5)
So __setitem__ is being called on the sliced copy, leaving the original list intact.

Categories