I have a list, let's say, a = [[1,2],[3,4],[5,6]]
I want to add the string 'a'
to each item in the list a
.
When I use:
a = [x.append('a') for x in a]
it returns [None,None,None]
.
But if I use:
a1 = [x.append('a') for x in a]
then it does something odd.
a
, but not a1
is [[1,2,'a'],[3,4,'a'],[5,6,'a']]
.
I don't understand why the first call returns [None, None, None]
nor why the second changes on a
instead of a1
.
leave the
a =
and use the side effect ona
:list.append
mutates the list itself and returnsNone
. List comprehensions are for storing the result, which isn't what you want in this case if you want to just change the original lists.(This is a combination of the answers by Mike Graham and sykora):
If you merely want to change the values in-place, try a regular for-loop, and not a list comprehension:
If you want to leave a alone, and put the result in a1:
As they explained,
append
modifies the list, but returns None, while+
leaves the list alone, but returns a new, appended list.For the first case, the reason it returns
[None, None, None]
is because thelist.append
function returnsNone
, and that's what it stores in the list.In the second case, it's because the list is mutable, and each time you append the value, the original list is modified.
What you need is a non-in-place append operator, such as
+
. i.e.[x + ['a'] for x in a]
.As others have said,
append
mutates the list itself and you shouldn't assign it to a variable. Executing it changes it's data, effectively updating everyone pointing at it.But, there's a trick I use when I want to do stuff in a functional* way while mutating existing objects (rather than constructing new ones, in this case using
a=[x + ['a'] for x in a]
, or specifically thex + ['a']
).So, if you're brave enough you can also do this:
This works because
append
returnsNone
, and theor
continues on to search for a truth-y value, whichx
is (it's alist
with at least what was appended to it).Why do I even need this?
Say you have a list and you want to insert some of it's members to a new list, and update the references accordingly:
So you have the list
all
:Some of it is inserted and updated to a new list
x
:Some of
all
is also inserted and updated to a listy
:all
is updated:But
x
is also updated:And
y
is generated as expected:Overall, for simple tasks, I'd recommend using a
for
loop updating explicitly. This is what's considered pythonic.Technically speaking, if you had access to the list class, you could make this a function:
append
is not very functional since it mutates a list (pure functional programming has only immutable objects) and does not return a result to pass to other actions (functions). Using functional programming concepts you can create great big one-liners no one can read, also known as "job security" or "bad code".In the first value assignment of your list comprehension an Attribute Error, 'NoneType' object has no attribute 'append', helps explain why your list, a, will be loaded with None(s). To get my console to throw the error, I used x as a variable for the list comprehension and also as the iterator.
Then, I reverted back to a for x and it threw the same error.