Python Basics — Lists, Dictionaries and Functions

The four data structures and the one language feature that every later lesson assumes you already know. This is the load-bearing lesson of the whole track.

Python Beginner 16 min read Watch the video (14:58)

Lesson 1 gave you one value at a time. That gets old fast — real programs handle collections: fifteen video titles, a hundred student scores, every word in a file.

This lesson is the load-bearing one. Everything after it assumes you know what is here.

#Lists — ordered, changeable, your default

A list holds things in order, and you can change it after the fact.

python
tracks = ["Python", "PHP", "Ruby", "C#", "Racket"]

print(tracks[0])      # Python   — counting starts at zero
print(tracks[2])      # Ruby
print(tracks[-1])     # Racket   — negative counts from the end
print(len(tracks))    # 5

tracks[-1] is the single most useful indexing trick in Python. You never have to write tracks[len(tracks) - 1] again.

#Changing a list

python
tracks.append("JavaScript")      # add to the end
tracks.insert(0, "Scratch")      # add at a position
tracks.remove("C#")              # delete by value
last = tracks.pop()              # remove and return the final item
tracks[1] = "Python 3"           # overwrite in place

#Slicing

A slice takes a range: list[start:stop], where stop is not included.

python
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

nums[2:5]     # [2, 3, 4]     — stops before index 5
nums[:3]      # [0, 1, 2]     — from the start
nums[7:]      # [7, 8, 9]     — to the end
nums[::2]     # [0, 2, 4, 6, 8]  — every second item
nums[::-1]    # [9, 8, ..., 0]   — reversed

nums[::-1] reverses a list in one expression. It works on strings too: "hello"[::-1] gives 'olleh'.

#Dictionaries — look things up by name

Lists answer "what is at position 3?" Dictionaries answer "what is the value for this key?" — which is usually the question you actually have.

python
video = {
    "title": "Intro to Python",
    "duration": "10:47",
    "views": 197,
    "track": "python",
}

print(video["title"])        # Intro to Python
video["views"] = 198         # update
video["published"] = 2020    # add a new key

Asking for a key that does not exist raises KeyError and stops your program. When a key might be missing, use .get():

python
video.get("likes")           # None — no crash
video.get("likes", 0)        # 0 — supply your own default

Looping over a dictionary gives you keys by default. Almost always, what you want is .items():

python
for key, value in video.items():
    print(f"{key:>10}: {value}")
text
     title: Intro to Python
  duration: 10:47
     views: 198
     track: python
 published: 2020

The :>10 right-aligns each key in a ten-character column. Small touch, much more readable output.

#Nesting is where it gets useful

Real data is a list of dictionaries:

python
catalogue = [
    {"title": "Intro to Python", "views": 197, "track": "python"},
    {"title": "PHP Web Form", "views": 259, "track": "php"},
    {"title": "Racket Download and Install", "views": 696, "track": "racket"},
]

for item in catalogue:
    print(f"{item['title']} — {item['views']} views")

total = sum(item["views"] for item in catalogue)
print(f"Total: {total} views")

#Tuples — a list that cannot change

Same syntax as a list, but with parentheses, and permanently frozen once created.

python
dimensions = (1920, 1080)
width, height = dimensions      # unpacking

Use a tuple when the number of items is part of the meaning: a coordinate pair, an RGB colour, a row from a database. If you would be alarmed to find a third item in there, it should be a tuple.

Tuples can also be dictionary keys. Lists cannot.

#Sets — unique things, fast membership tests

python
tags = {"python", "beginner", "python", "loops"}
print(tags)          # {'python', 'beginner', 'loops'} — duplicate gone

Two superpowers:

Deduplicating. list(set(items)) removes duplicates in one pass.

Speed. Checking x in some_set is effectively instant no matter how large the set is. Checking x in some_list scans every element. On a list of a million items, that difference is the difference between a program that finishes and one that does not.

Sets also do maths:

python
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

a & b     # {3, 4}          intersection — in both
a | b     # {1,2,3,4,5,6}   union — in either
a - b     # {1, 2}          difference — in a, not in b

Remember &. It turns a whole class of interview problems into a one-liner — including the Intersection of Two Arrays problem later in this course.

#Picking the right one

You needUseWhy
An ordered collection you will changelistThe default. Reach for it first.
Lookup by namedictInstant access by key
A fixed group that belongs togethertupleCannot be modified by accident
Unique items, or fast "is it in here?"setDeduplicates, and searches instantly

#Functions — name a block of work

A function packages up code so you can run it again without re-typing it.

python
def greet(name):
    return f"Hello, {name}!"

message = greet("Dom")
print(message)          # Hello, Dom!
  • def starts the definition.
  • Whatever is in the parentheses are the parameters — the inputs.
  • return hands a value back to whoever called it.

#Default values and keyword arguments

python
def format_duration(seconds, show_hours=False):
    minutes, secs = divmod(seconds, 60)
    if show_hours:
        hours, minutes = divmod(minutes, 60)
        return f"{hours}:{minutes:02d}:{secs:02d}"
    return f"{minutes}:{secs:02d}"

format_duration(647)                     # '10:47'
format_duration(647, show_hours=True)    # '0:10:47'

divmod(a, b) returns the quotient and remainder together — exactly what you want for time conversion. {secs:02d} pads with a leading zero so you get 10:07, not 10:7.

Naming the argument at the call site (show_hours=True) makes the code self-documenting. Compare format_duration(647, True) — true what?

#A function should do one thing

python
def average(numbers):
    if not numbers:
        return 0
    return sum(numbers) / len(numbers)


def summarise(scores):
    return {
        "count": len(scores),
        "average": round(average(scores), 1),
        "best": max(scores),
        "worst": min(scores),
    }


print(summarise([88, 92, 79, 95, 84]))
text
{'count': 5, 'average': 87.6, 'best': 95, 'worst': 79}

average guards against an empty list — without that check, len(numbers) is zero and you get ZeroDivisionError. Handling the empty case is the difference between code that works on your test data and code that works.

Note if not numbers: rather than if len(numbers) == 0:. In Python, empty collections are falsy. Same for "", 0, and None. It reads better and it is the idiom you will see everywhere.

Check yourself

4 questions on what you just read. No score is kept — it is only here to catch the bits that did not stick.

  1. 1What does nums[2:5] return from nums = [0,1,2,3,4,5,6]?

    Show the answer

    A. [2, 3, 4]

    The stop index is excluded. That is exactly what makes nums[:3] and nums[3:] split a list with no overlap and nothing missing.

  2. 2A key might not exist in a dictionary. Which access will not crash?

    Show the answer

    A. video.get("likes", 0)

    Square brackets raise KeyError and stop the program. .get() returns None, or whatever default you pass.

  3. 3You need to check membership against a million items, repeatedly. What should hold them?

    Show the answer

    A. A set — lookups are effectively instant regardless of size.

    x in some_list scans every element. x in some_set hashes straight to the answer. On large data that is the difference between finishing and not.

  4. 4What is wrong with a function that only prints its result?

    Show the answer

    A. The caller cannot use the value for anything.

    print shows a value to a human; return hands it back to your program. A function that only prints is a dead end.

#Key takeaways

  • Lists are ordered and changeable; index from 0, or from -1 at the end.
  • Slices exclude the stop index — that is what makes a[:n] and a[n:] split cleanly.
  • Dictionaries map keys to values. Use .get() when a key might be missing, .items() when looping.
  • Sets deduplicate and test membership instantly. &, | and - do real set maths.
  • Functions return values; print is only for humans. Guard your edge cases.

Next: loops, and the comprehension syntax that replaces most of them.

Finished this one?

The challenge above has no posted solution — that is deliberate. Get it working, then come back for the next lesson.

Next lesson Subscribe