Create your own
Lesson illustration

From Pseudocode to Tested Code

Hi. You have now built the core pieces needed to write small Python programs: collections, conditionals, functions, loops, and a systematic debugging method. This lesson combines them into one complete workflow: start from a short plan, implement it, consult documentation for one unfamiliar piece of syntax, test the result, and explain the program without relying on the code alone.

This is a high-leverage research habit. In ML work, a small data-filtering function may decide which runs are analyzed or which samples enter training. The code can be short, but its assumptions and tests matter.

By the end, you will have a reusable pattern for turning a stated procedure into a trustworthy Python program.


The 80/20 implementation loop

When a program is more than a one-line calculation, avoid trying to write perfect code in one pass. Use this compact loop:

  1. State the input and intended output.
  2. Write plain-language pseudocode that captures decisions and repetition.
  3. Translate one pseudocode line at a time into Python.
  4. Use documentation when you know what should happen but not the exact syntax.
  5. Test cases with known answers.
  6. Explain the code’s behavior and assumptions in your own words.

Pseudocode is not “bad Python.” It is a language-independent plan. Its job is to clarify the logic before Python’s punctuation, indentation, and exact method names compete for your attention.

What is Pseudocode Explained | How to Write Pseudocode Algorithm | Examples, Benefits & Steps

Watch “What is Pseudocode Explained” from Learn with Whiteboard for a short visual overview of planning, checking, and translating a program.

Watch the definition to distinguish pseudocode from real code. Then watch the workflow and the example. Focus on the crucial idea that you can manually check a plan with an example before writing Python.

The task: select qualifying experiment runs

Imagine you have results from three agent-training runs. Each run has:

  • an ID,
  • a final reward,
  • whether the run completed successfully.

You want a function that returns the IDs of runs that both:

  • completed successfully, and
  • reached at least a chosen minimum reward.

Here is the input data:

runs = [
    {"id": "run_01", "reward": 18, "completed": True},
    {"id": "run_02", "reward": 7, "completed": True},
    {"id": "run_03", "reward": 22, "completed": False},
]

If the minimum reward is 10, the desired result is:

["run_01"]

run_02 completed but has too little reward. run_03 has a high reward but did not complete, so it does not qualify.

Write the plan first

A useful pseudocode version is:

DEFINE a function that receives runs and a minimum reward
CREATE an empty list for qualifying IDs

FOR each run in runs:
    IF the run completed AND its reward is at least the minimum:
        ADD its ID to the qualifying list

RETURN the qualifying list

Notice what this plan makes explicit:

Plan elementWhy it matters
Function inputsThe program needs a collection of runs and a threshold.
Empty result listThere must be somewhere to collect matching IDs.
FOR each runThe same rule is applied to every run.
IF ... AND ...Both requirements must hold; one is not enough.
RETURNThe function gives a result back rather than merely displaying it.

Before implementing, manually trace the plan with the three runs. Start with an empty result list. Only run_01 passes both checks, so the final list should contain just "run_01". This is your first expected result—and therefore your first test oracle.


Translating the plan into Python

Here is a direct implementation:

def qualified_run_ids(runs, minimum_reward):
    qualified_ids = []

    for run in runs:
        if run["completed"] and run["reward"] >= minimum_reward:
            qualified_ids.append(run["id"])

    return qualified_ids

Read it as a translation, not as a block to memorize:

PseudocodePythonMeaning
Define a functiondef qualified_run_ids(runs, minimum_reward):Create a reusable operation with two inputs.
Create an empty listqualified_ids = []Prepare a place to store successful IDs.
For each runfor run in runs:Visit one dictionary at a time.
Check both conditionsif ... and ...:Keep only runs that meet both rules.
Add its IDqualified_ids.append(run["id"])Put the selected ID into the result list.
Return the resultreturn qualified_idsGive the completed list back to the caller.

Two details deserve careful attention.

First, each run is a dictionary. Therefore, expressions such as run["reward"] retrieve a value using a key. This code assumes every run has all three keys: "id", "reward", and "completed". If one is absent, Python will raise a KeyError, which is useful evidence that the data does not match the expected structure.

Second, and means both conditions must be true. In this application, a high reward alone is not evidence of a valid completed run.

Documentation is for exact syntax, not for guessing logic

You already know the intended operation: add one selected ID to a list. The syntax that does this is:

qualified_ids.append(run["id"])

It is reasonable not to remember whether this is called append, add, or something else. That is exactly when documentation is useful.

Python Documentation - How to Read and Browse the Python Docs

Watch “Python Documentation - How to Read and Browse the Python Docs” by Coding with Estefania to practise finding a function entry and extracting only the information needed to use it.

Watch the Library Reference to see where standard Python functions and types are documented. Then watch reading an entry, which uses len() to show how to identify a function’s parameter, accepted input, and returned value.

For this program, use the same documentation-reading method:

  1. Go to the official Python documentation as shown in the video.
  2. Search for list.append.
  3. Locate its signature, commonly shown as list.append(x).
  4. Read the short description to check what it changes and whether it returns a new list.
  5. Return to your program and use the syntax deliberately.

This takes less time than searching randomly or asking an AI to guess, and it gives you a traceable source for decisions in larger projects.

A common mistake is to write this:

qualified_ids = qualified_ids.append(run["id"])

Do not do that. append changes the existing list in place; it is not a function that produces a replacement list. The correct form is simply:

qualified_ids.append(run["id"])

Run and test the complete program

Combine the function, data, and tests in one short script:

def qualified_run_ids(runs, minimum_reward):
    qualified_ids = []

    for run in runs:
        if run["completed"] and run["reward"] >= minimum_reward:
            qualified_ids.append(run["id"])

    return qualified_ids


runs = [
    {"id": "run_01", "reward": 18, "completed": True},
    {"id": "run_02", "reward": 7, "completed": True},
    {"id": "run_03", "reward": 22, "completed": False},
]

assert qualified_run_ids(runs, 10) == ["run_01"]
assert qualified_run_ids(runs, 0) == ["run_01", "run_02"]
assert qualified_run_ids(runs, 30) == []

print("All tests passed.")
print("Qualified IDs:", qualified_run_ids(runs, 10))

Expected output:

All tests passed.
Qualified IDs: ['run_01']

These three tests examine different logical cases:

TestWhat it checks
Threshold 10The normal case: one run qualifies.
Threshold 0Completed runs qualify even if their reward is small.
Threshold 30The function correctly returns an empty list when no runs qualify.

The second test is particularly valuable because it confirms that incomplete run_03 stays excluded even though its reward is above 0. A single test can accidentally pass while leaving part of the intended rule untested.

Visual trace: watch the list being built

A loop can feel abstract because the same code executes several times with different values. A visualizer makes the changing state concrete.

A Python Tutor snapshot after line 5 of a short program: the variable `x` has been reassigned from `"Hello"` to `"World"`, while `y` still refers to `"Hello"`; the output panel shows the text printed so far. This illustrates that execution proceeds one line at a time and variables can hold different values as the program changes state.

Visualize code in Python, JavaScript, C, C++, and Java

Use Python Tutor’s “Visualize code execution” tool to step through the program and inspect how run and qualified_ids change on each loop iteration.

In the main editor, select Python, paste the complete program above, and click “Visualize Execution.” In the Demo section, read the controls before tracing your own code. Although the illustrated demo uses Java, the same essential controls apply: move forward and backward through executed lines, inspect variables in the current function frame, and compare printed output with the current state. For your program, pause each time the line if run["completed"] ... is highlighted. Watch run change from run_01 to run_02 to run_03, and observe that qualified_ids changes only during the first iteration. Finally, step to return qualified_ids and confirm that the returned list is ['run_01'].

When tracing, focus on this state table:

Current runCompleted?Reward reaches 10?Does qualified_ids change?
run_01YesYesIt becomes ["run_01"]
run_02YesNoNo change
run_03NoYesNo change

If your output differs, use the debugging routine from the previous lesson: read any traceback from the bottom, locate the relevant line, explain the mismatch, apply the smallest correction, and rerun the same tests.


Explain the program without reciting it

Being able to explain code is a separate skill from making it run. A clear explanation identifies the inputs, process, output, and assumptions.

Here is a model explanation:

qualified_run_ids takes a list of experiment-run dictionaries and a minimum reward. It creates an empty list, then checks each run in turn. A run is selected only when its completed value is True and its reward is at least the threshold. The function returns the selected IDs as a new list. It assumes each input dictionary contains valid id, reward, and completed fields.

This explanation is useful because it says what rule the code implements. It also names an important limitation: malformed or incomplete run data is outside the function’s current contract.

For research code, this is the minimum level of explanation worth preserving in a README, experiment note, or code comment. A future reader should be able to tell whether filtering incomplete runs is an intentional experimental decision rather than an accidental side effect.

A reusable implementation card

Add this compact card to your visual knowledge system:

From pseudocode to tested Python

  • Define the inputs and expected output with one tiny example.
  • Write the decision and repetition rules in plain language.
  • Translate each rule into a small piece of Python.
  • Look up unfamiliar syntax in official documentation; check the signature, input, return behavior, and example.
  • Use assert with normal, boundary, and empty-result cases.
  • Trace one example visually when a loop or changing state is confusing.
  • Explain the inputs, rule, output, and assumptions in plain language.

Key takeaways

A short program becomes more reliable when you separate its logic from its syntax:

  • Pseudocode clarifies what the program should do before implementation begins.
  • Python turns that plan into functions, loops, conditionals, and collection operations.
  • Documentation resolves precise syntax questions, such as how to add an item to a list.
  • Tests with known expected outputs verify behavior beyond “the script ran without an error.”
  • A plain-language explanation makes the program’s purpose and assumptions inspectable.

You have now completed the independent-Python foundation for the course. The next module shifts to the mathematical language used throughout ML: linear equations, functions, vectors, and matrices.

Can't find a good explanation? Sign up and we'll make it for you

Sign up