Python: Level 2 (Intermediate)

The next step up: the everyday Python that makes you genuinely productive, comprehensions, cleaner loops, handling messy data without crashing, and organising your code, all taught gently and at your own pace.

🟡 Intermediate ⏱️ ~2 hr 🐍 Python

You are ready for this if...

You have finished Python Basics and you are comfortable with variables, lists, dictionaries, a simple loop, and writing a small function. If any of that feels shaky, there is no rush at all: go back, play with it, and come here whenever you feel like it. Nothing on this page is a race.

No memorizing required. Read each idea once, run the cell, change something, run it again. That is the whole method. You can always come back to this page later as a reference.

1. Comprehensions: a shorter way to build a list

["ATGC","GGG","AT"] the original list len(s) for each [4, 3, 2] a new list
A comprehension applies one expression to every item and collects the results into a new list.

You already know how to build a list with a loop. A comprehension does the same thing in one readable line. Here is the same task written both ways.

# The familiar way
seqs = ["ATGC", "GGGCCC", "ATATAT"]
lengths = []
for s in seqs:
    lengths.append(len(s))

# The same result as a comprehension
lengths = [len(s) for s in seqs]

Read it right to left: "for each s in seqs, give me len(s)." You can build dictionaries the same way. Run this and change the sequences.

When NOT to use one

Comprehensions are lovely for simple "make a new list from an old one" tasks. If the logic needs several steps or a few if branches, a normal loop is clearer. Clear beats clever every time.

2. enumerate and zip: cleaner loops

Two small built-ins remove a lot of clumsy code. enumerate gives you a counter while you loop; zip walks two lists together.

3. while loops, break, and continue

A for loop runs a set number of times. A while loop runs until a condition stops being true. break leaves the loop early; continue skips to the next turn.

4. Handling errors without crashing

try: run the code works fails you get the result carry on as normal except: handle it recover, no crash
try runs your code. If it works you get the result; if it fails, except catches the error so the program keeps going.

Real data is messy. A single empty line or odd value can stop a whole script. try / except lets your code recover instead of crashing.

Catch only what you expect

Name the specific error (here, ZeroDivisionError) rather than catching everything. A blanket except can hide real bugs by swallowing errors you actually wanted to see.

5. Functions that go a little further

You can give a function default values so callers can skip arguments, and you can return more than one value at once.

6. Splitting code into scripts and modules

So far your code has lived in one notebook or cell. As projects grow, you move it into a .py script you can run from the terminal, and you can keep reusable functions in their own file (a module) and import them.

# file: seqtools.py  (your own module of helpers)
def gc_content(seq):
    return round((seq.count("G") + seq.count("C")) / len(seq) * 100, 1)

# file: analyze.py  (uses the helper)
from seqtools import gc_content
print(gc_content("ATGGGC"))

Why bother

One giant file is hard to read and reuse. Small modules let you write a function once and use it in every analysis, which is exactly how real bioinformatics code is organised. When you are ready to work this way, the graduate-to-a-pro-setup lesson shows you how.

7. Pattern matching with regular expressions optional on first pass

A regular expression ("regex") is a mini-language for finding patterns in text, perfect for pulling IDs or coordinates out of messy headers. The re module is built in, so this runs as-is.

What do those symbols mean?
\w   a word character (letter, digit, or underscore)
\d   a digit
+    one or more of the previous thing
( )  a group you want to capture and read back
re.search   find the first match
re.findall  return every match as a list

8. NumPy: fast maths on whole arrays optional on first pass

NumPy stores numbers in an array and does maths on the whole thing at once, far faster than a Python loop. This is the engine under pandas and almost every scientific library. (NumPy needs to be installed, so run this one in Colab rather than the cell above.)

import numpy as np

expr = np.array([12.4, 8.1, 15.7, 3.3, 9.9])
print(expr.mean(), expr.max())   # summary numbers in one step
print(expr * 2)                  # doubles every value at once
print(expr[expr > 10])             # keep only values above 10

Where this goes next

Two tools turn these basics into real data analysis, and you already have lessons for both:

Practice exercises

Try each in the cell before opening the solution. You cannot break anything.

Exercise 1: comprehension. Given a list of sequences, build a list of just their lengths using a comprehension.

Show a worked solution
seqs = ["ATG", "GGGGCC", "AT"]
lengths = [len(s) for s in seqs]
print(lengths)   # [3, 6, 2]

Exercise 2: pair two lists. Print each gene next to its expression value using zip.

Show a worked solution
for g, e in zip(genes, expr):
    print(g, e)

Exercise 3: handle the empty case. Write first_base(seq) that returns the first base, or the string "empty" if the sequence has no bases.

Show a worked solution
def first_base(seq):
    try:
        return seq[0]
    except IndexError:
        return "empty"

print(first_base("ATGC"))   # A
print(first_base(""))       # empty

Check your understanding

Correct. break exits the loop entirely. (The one that skips just the current turn is continue.)
Right. Returning comma-separated values gives back a tuple, so length, gc = seq_stats(...) unpacks both at once.
Exactly. A module lets one tested function serve every analysis, which is how real bioinformatics code is organised.
Exactly. Real data is messy. Catching the specific error lets the loop skip the bad file and keep processing the rest.
Right. A list comprehension builds a new list by applying an expression (here len(s)) to every item.
Exactly. Real data is messy; catching the specific error you expect lets the program recover and keep going.
Correct. zip pairs up items from two (or more) lists so you can loop over them side by side.
Put these skills to work on real tables

Pandas for biologists →

Level 3 (Advanced): NumPy in depth, virtual environments, testing, and automation is coming next.