EduFlow

Section 1 · Python Essentials for Analysts

Functions, f-strings and Reading Errors

20 min3 min readPython exercise

Lesson at a glance

Package repeated logic into functions with parameters and return values, format numbers for reports with f-strings, and read a Python traceback to find and fix the real problem.

  1. 1Defining a function
  2. 2Cleaning functions
  3. 3f-strings: numbers people can read
  4. 4Reading errors without panic

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

By now you have cleaned the price " $129.00" once, computed a line’s revenue once, and printed a few numbers. Cartwheel has 3,991 order lines. You do not want to copy the cleaning code to every place it is needed and then fix a bug in seven copies. Functions let you write the logic once, give it a name, and call it wherever you need it.

Defining a function

Python
def line_revenue(quantity, unit_price, discount=0.0):
    """Revenue of one order line: quantity x price, minus the discount."""
    return round(quantity * unit_price * (1 - discount), 2)

print(line_revenue(2, 129.0, 0.15))   # 219.3
print(line_revenue(1, 39.0))          # discount defaults to 0.0
print(line_revenue(quantity=3, unit_price=24.0, discount=0.25))

The pieces: def, the function’s name, parameters in parentheses, a colon, and an indented body. discount=0.0 is a default, used when the caller leaves it out. The triple-quoted line under def is a docstring, which documents what the function does; editors show it when you hover over the name.

return sends a value back to the caller, and the call line_revenue(2, 129.0, 0.15) becomes that value. You can store it, add it, pass it to another function. Calling with names, as in the third example, makes long argument lists readable and protects you from swapping two numbers by accident.

Cleaning functions

Here is the money cleaner from Lesson 1.2, made reusable. It handles the dollar sign, stray spaces and thousands separators:

Python
def parse_money(text):
    """Turn strings like ' $1,234.50' into the float 1234.5."""
    cleaned = text.strip().replace("$", "").replace(",", "")
    return float(cleaned)

for raw in [" $129.00", "18.00", "$1,234.50"]:
    print(raw, "->", parse_money(raw))

Give functions verb names that say what they return (parse_money, line_revenue, clean_country) and keep each one to a single job; small functions are easy to test with a couple of print calls like the loop above. Now every messy total in the export can go through one tested function. If you discover a new format next month (say, a trailing USD), you fix it in one place.

f-strings: numbers people can read

A report that says 146825.4412 makes readers squint. An f-string, a string with f before the opening quote, lets you drop values into text inside {} and format them with a spec after a colon:

Python
revenue = 146825.4412
orders = 642
share = 0.4493

print(f"Q4 2025 revenue: ${revenue:,.2f}")       # thousands separator, 2 decimals
print(f"Orders: {orders}, average {revenue / orders:.2f} per order")
print(f"Share of the year: {share:.1%}")          # percent with 1 decimal
print(f"|{'Egypt':<12}|{orders:>6}|")             # left- and right-aligned columns

The specs you will use most: ,.2f for money, .1% for shares (it multiplies by 100 for you), ,.0f for large whole numbers, and </> with a width for aligned text. Any expression works inside the braces, including arithmetic like revenue / orders.

Reading errors without panic

When Python cannot continue, it raises an exception and prints a traceback. Beginners read it from the top and get lost. Read it from the bottom:

Text
Traceback (most recent call last):
  File "report.py", line 9, in <module>
    total = parse_money(row["Total"])
                        ~~~^^^^^^^^^
KeyError: 'Total'

The last line is the error type and message: a dictionary was asked for the key 'Total' and does not have it. One line up is the code that failed, with markers under the exact expression, and above that, the file and line number. The fix here is the column’s real name, 'total'.

A traceback in three layers. Bottom: the error type and message, read first. Middle: the failing line of code with markers. Top: the file and line number, used to find the place in your code. File "report.py", line 9 total = parse_money(row["Total"]) KeyError: 'Total' 1. what went wrong 2. which expression 3. where to look
Read a traceback from the bottom up

The errors you will meet most, and what they almost always mean:

Error Usual cause
NameError A typo in a variable name, or using it before assigning it
KeyError A dictionary key or DataFrame column that does not exist (check spelling and case)
TypeError Mixing types, such as text plus a number, or calling a function with the wrong arguments
ValueError The type is right but the content is not, such as float("$65.00")
IndexError A list position past the end
AttributeError Calling a method the value does not have, often on None

Handling an error you expect

Some failures are part of the data, not bugs. A messy total such as "N/A" will never become a number. try / except lets you decide what happens instead:

Python
def parse_money_or_none(text):
    try:
        return float(text.strip().replace("$", "").replace(",", ""))
    except ValueError:
        return None

print(parse_money_or_none("$65.00"), parse_money_or_none("N/A"))

Catch the specific exception you expect (ValueError here) and nothing else. A bare except: would also swallow a typo in your own code, and you would get None everywhere with no clue why.

That completes your Python toolkit. Section 2 puts it to work at scale: pandas, where a single line operates on every row of a table.

Key takeaways

  • A function names a piece of logic; parameters are its inputs and return hands back its output.
  • A function that prints instead of returning gives back None, so its result cannot be used in further calculations.
  • f-strings format values inline: f"{revenue:,.2f}" gives 1,234.50 and f"{share:.1%}" gives 12.5%.
  • Read a traceback from the bottom - the last line names the error type and message, the lines above show where it happened.
  • try / except handles an error you expect, such as text that cannot become a number; never use it to hide errors you do not understand.

Further reading

Check your understanding

4 questions

Question 1 of 4

What is result after this runs?

Python
def add_tax(amount):
    print(amount * 1.2)

result = add_tax(100)
Question 2 of 4

Which f-string prints Revenue: $146,825.44 when revenue = 146825.4412?

Question 3 of 4

The last line of a traceback reads:

Text
KeyError: 'Total'

What is the most likely cause?

Question 4 of 4

When is wrapping code in try / except a good idea?

Practice

Python exercise

Three helper functions for the report

Complete three functions. parse_money(text) returns a float from strings like " $1,234.50", "$129.00" or "18.00". line_revenue(quantity, unit_price, discount=0.0) returns quantity × unit price × (1 − discount), rounded to 2 decimals; the discount defaults to 0. format_money(amount) returns a string like "$1,234.50": a dollar sign, thousands separators and exactly two decimals. Each function must return its result, not print it.

def parse_money(text):
    """' $1,234.50' -> 1234.5"""
    pass


def line_revenue(quantity, unit_price, discount=0.0):
    """quantity x unit_price x (1 - discount), rounded to 2 decimals"""
    pass


def format_money(amount):
    """1234.5 -> '$1,234.50'"""
    pass


print(parse_money(" $1,234.50"), line_revenue(2, 129.0, 0.15), format_money(1234.5))
Loading the editor…

Ctrl/⌘ + Enter to run · Runs in a sandbox in your browser. Nothing leaves your device.

(no output)

Checks

  • parse_money handles "18.00" and " $129.00"
  • parse_money handles thousands separators: "$1,234.50" becomes 1234.5
  • line_revenue applies the discount and rounds to 2 decimals
  • line_revenue works without a discount argument
  • format_money(1234.5) returns "$1,234.50"