0

Quick question from someone with limited Python experience. So I have some lists inside a list. I want to iterate through it, append something to each iteration, and then store that in a different list.

For example:

var=[[1],[2],[3]]
var2 = []

for item in var:
    var2.append(item.append("x"))

However, rather than the expected output for var2 of [[1, 'x'], [2, 'x'], [3, 'x']] I get [None, None, None]

I was planning to reuse my original variable, var, for a different purpose. However, var is now equal to [[1, 'x'], [2, 'x'], [3, 'x']]

What is going on here?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Alex Heebs
  • 740
  • 1
  • 8
  • 16
  • 3
    [`item.append()` modifies `item` and returns `None`](https://stackoverflow.com/questions/16641119/why-does-append-always-return-none-in-python) – pault Dec 04 '19 at 22:41
  • I think you want to do `var2.append([item[0], "x"]) ` – Moshe Rabaev Dec 04 '19 at 22:43
  • 1
    Try `item + ["x"]` instead – Robin Zigmond Dec 04 '19 at 22:43
  • 1
    `var2.append(item + ['x'])` – Chris Doyle Dec 04 '19 at 22:44
  • Use item + ['x'] – Marcin Świerczyna Dec 04 '19 at 22:45
  • @MosheRabaev: Or to handle potentially longer `item` `list`s, `item + ['x']` or `[*item, 'x']` (the latter Py3 only) would both work. – ShadowRanger Dec 04 '19 at 22:45
  • Assign your item to a temprary variable then update it `for item in var: ... tmp = item ... tmp.append('x') ... var2.append(tmp)` – Ersel Er Dec 04 '19 at 22:46
  • 1
    I have a meta question, trying to figure out when to comment vs answer. How come none of you posted an answer? I always feel like I'm doing something wrong because it seems like everyone just answers questions in the comments instead of posting answers – swaggy p Dec 04 '19 at 22:48
  • @swaggyp I didn't answer because I was pretty sure I could find a dupe for this question...but there's actually two things going on here so it's a little more nuanced. Probably worth an answer... – pault Dec 04 '19 at 22:50
  • @Alex see also: [How to clone or copy a list?](https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list) and (tangentially related, but useful) [List of lists changes reflected across sublists unexpectedly](https://stackoverflow.com/questions/240178/list-of-lists-changes-reflected-across-sublists-unexpectedly) – pault Dec 04 '19 at 22:57

3 Answers3

4

The append function modifies its input. So when you call item.append(...), you are modifying item, which is a reference to one of the elements in var.

You can minimally reproduce this via

var=[[1],[2],[3]]

for item in var:
    item.append("x")

In addition, the return value of append is None, so you're effectively calling var2.append(None) for each item, explaining your var2 result.

To avoid this, use a non-destructive method that returns the value you want, such as

var=[[1],[2],[3]]
var2 = []

for item in var:
    var2.append(item + ["x"])

Or, better still,

var=[[1],[2],[3]]
var2 = [item + ["x"] for item in var]
Andrew Schwartz
  • 4,440
  • 3
  • 25
  • 58
2

If you refer to the docs list.append as well as others return None and that's what you're appending. Therefore you need to concatenate or extend the list while returning the value. I suggest using item + ['x'] so your loop would look as follows:

for item in var:
    var2.append(item + ['x'])

Although why not just use a list comprehension for this?

var=[[1],[2],[3]]
var2 = [item + ['x'] for item in var]

Results:

[[1, 'x'], [2, 'x'], [3, 'x']]
Jab
  • 26,853
  • 21
  • 75
  • 114
0

Your for loop is the culprit. This is not that hard but we have to make sure what is going on in the nested list appends.

My solution to this would be:

var=[[1],[2],[3]]
var2 = []

for i in range(len(var)):
  list = []
  list.append(var[i][0])
  list.append('x')
  var2.append(list)

print(var)
print(var2)
>>> [[1], [2], [3]]
>>> [[1, 'x'], [2, 'x'], [3, 'x']]

Even though it may be intuitive to write:

for list in var:
  list.append('x')
  var2.append(newList)

This will change the values in the lists in the original var list as well.