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.
- 1Defining a function
- 2Cleaning functions
- 3f-strings: numbers people can read
- 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
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:
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:
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 columnsThe 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:
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'.
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:
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
returnhands 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}"gives1,234.50andf"{share:.1%}"gives12.5%. - Read a traceback from the bottom - the last line names the error type and message, the lines above show where it happened.
try/excepthandles an error you expect, such as text that cannot become a number; never use it to hide errors you do not understand.