Programming and IT

Python: lists

A list is a mutable, ordered collection of values of any type. It is also the main source of surprises for beginners: assignment does not copy a list, sort returns nothing, and removing items inside a loop skips half of them. Let us go through it in order.

Updated
In this article

Creating a list and what goes inside#

A list is written in square brackets; the items can be of different types, and that is fine, although in real code a list of one type is easier to work with.

nums = [3, 1, 2]
mixed = [1, "two", 3.0, [4]]
empty = []
print(len(nums), nums[0], nums[-1])   # 3 3 2

Indexing starts at zero, and negative indexes count from the end: -1 is the last item. Going past the end raises IndexError rather than returning an empty value.

Adding and removing#

items = ["a", "b"]
items.append("c")          # ['a', 'b', 'c']
items.extend(["d", "e"])   # ['a', 'b', 'c', 'd', 'e']
items.insert(1, "x")       # ['a', 'x', 'b', 'c', 'd', 'e']
items.remove("x")          # removes the FIRST occurrence
last = items.pop()         # 'e', the list got shorter
print(items, last)         # ['a', 'b', 'c', 'd'] e

Learn the difference between append and extend right away: the first adds its argument as a single item, the second unpacks it item by item.

a = [1, 2]
a.append([3, 4])
print(a)          # [1, 2, [3, 4]]
b = [1, 2]
b.extend([3, 4])
print(b)          # [1, 2, 3, 4]

remove raises ValueError if the value is not there, and pop(i) raises IndexError for a bad index. To delete by index without getting the value back, use del items[0].

Sorting: sort and sorted#

words = ["melon", "Apple", "plum"]
print(sorted(words, key=len))      # ['plum', 'melon', 'Apple']
print(sorted(words, reverse=True)) # ['plum', 'melon', 'Apple']
print(words.sort())                # None
print(words)                       # ['Apple', 'melon', 'plum']

The sort method changes the list in place and returns None — the line words = words.sort() turns your list into None, and that is a common mistake. The sorted function returns a new list and works with any sequence. The key argument says what to compare by: key=len — by length, key=str.lower — ignoring case. A capital letter compares by its character code and therefore comes before lowercase letters: Apple landed before melon. Sorting is stable — items with equal keys keep their original order: in the key=len example, the five-letter melon and Apple stayed in the order they were in.

Copying: assignment does not copy#

a = [1, 2, 3]
b = a
b.append(4)
print(a)        # [1, 2, 3, 4]  — a changed too

c = a.copy()    # or list(a), or a[:]
c.append(5)
print(a, c)     # [1, 2, 3, 4] [1, 2, 3, 4, 5]

b = a gives a second name to the same object. A real copy is a.copy(), list(a) or the slice a[:]. But all three are shallow copies: nested lists stay shared.

table = [[0, 0], [0, 0]]
shallow = table.copy()
shallow[0][0] = 9
print(table)    # [[9, 0], [0, 0]]

For a deep copy, use copy.deepcopy. For the same reason, grid = [[0] * 3] * 3 is dangerous: the outer list gets three references to one row, and grid[0][0] = 1 changes all three. The right way is [[0] * 3 for _ in range(3)].

List comprehensions and iteration#

squares = [x * x for x in range(5)]
print(squares)                                # [0, 1, 4, 9, 16]
print([x for x in squares if x % 2 == 0])     # [0, 4, 16]

for i, value in enumerate(["a", "b"], start=1):
    print(i, value)                           # 1 a / 2 b

A list comprehension reads as "what to collect — from what — under which condition", and it is almost always shorter than a loop with append.

A separate trap is changing a list while a loop is going over it:

nums = [1, 2, 2, 3]
for n in nums:
    if n == 2:
        nums.remove(n)
print(nums)     # [1, 2, 3] — one 2 survived

The loop walks by index, and the list shifted after the removal. The right approach is to build a new list: nums = [n for n in nums if n != 2].

An exercise to make it stick: from the list of scores [4, 5, 3, 5, 4, 2], get a list without duplicates sorted in descending order, and separately the number of scores above three. Each answer fits on one line.

Related topics: Python slicing for taking pieces of a list, and Python dictionaries for when you need access by key rather than by position.

Step-by-step plan

  1. Create and loopA list of ten numbers: print its length, the first and last item, then loop with enumerate.
  2. Five changing methodsappend, extend, insert, remove, pop — print the list after each one and see the difference.
  3. Sort three wayssort, sorted, sorted with key=len; make sure sort returned None.
  4. A copying experimentb = a and c = a.copy(): change each one and compare what happened to a.
  5. Rewrite a loop as a comprehensionReplace a loop with append by a list comprehension with a condition.

Start learning this in your own space

The plan goes into your repository: tick off stages, keep notes — the change history shows how far you have come.

Start the plan

Check yourself

1.What does this print: a = [1, 2]; a.append([3, 4]); print(len(a))?

2.What does print([1, 2, 3].sort()) print?

3.What does this print: a = [1, 2]; b = a; b.append(3); print(a)?

4.What is len([x for x in range(10) if x % 3 == 0])?

Sources

Was this helpful?

More articles

Programming and IT Python: slicing A slice cuts a piece out of a sequence by the rule "from which index, up to which, with what step". The notation is compact, but it has two places where almost everyone slips: the right bound is not included, and with a negative step the bounds swap places. Let us go through both. Programming and IT Python: strings A string in Python is an immutable sequence of characters. Almost all of its quirks follow from that: methods do not change a string but return a new one, and fast text building goes through join, not through adding strings in a loop. Below is the working minimum with examples and output. Programming and IT Python: dictionaries A dictionary stores key–value pairs and finds a value by its key in constant time, however large it grows. It is the workhorse for counting, grouping and settings. Below: creating dictionaries, safe access, iteration and the places where a dictionary does not behave the way people expect. Programming and IT How to learn Python from scratch Python is a good first programming language: code reads almost like text, and the standard library covers most everyday tasks. This plan takes you from installing the interpreter to your own scripts covered by tests in about four months, at roughly an hour a day. Programming and IT Python: classes A class describes what data an object is made of and what it can do. The `__init__` constructor fills in a new object, and `self` is a reference to the object itself. Below: a minimal working class, the difference between class and instance attributes, and ways to make the code shorter. Programming and IT Python: functions A function is a named piece of code that takes values and returns a result. In Python a definition takes one line, but arguments have subtleties: defaults are evaluated once, positional and keyword arguments mix by rules, and a function without return still returns something.

More solutions