Featured resource
2026 Tech Forecast
2026 Tech Forecast

1,500+ tech insiders, business leaders, and Pluralsight Authors share their predictions on what’s shifting fastest and how to stay ahead.

Download the forecast
  • Lab
    • Libraries: If you want this lab, consider one of these libraries.
    • Core Tech
Labs

Mastering Python Functions

Every Python script starts innocently: ten lines, one goal, total control. Then comes a quick fix. Then another. Then a function called do_stuff() that slowly becomes the entire application. Six months later, you open the file and whisper: “Who wrote this?” … And surprise—it was you. Functions are how you fight back. In this hands-on Code Lab, you will learn how to design, create, and apply Python functions using parameters, return values, and modular programming techniques to solve real problems efficiently. You will start with simple def blocks, then level up to building flexible, reusable functions that transform copy-paste chaos into clean, maintainable code. Along the way, you will break larger problems into smaller pieces, pass data cleanly between functions (input → process → output), and build solutions that are easier to read, test, and debug—even at 2 AM. By the end of the lab, you will think in functions: split the problem, name the pieces, wire them together, and ship code that still makes sense tomorrow. Cleaner Python. Less panic. A slightly happier future version of you.

Lab platform
Lab Info
Level
Beginner
Last updated
Jun 26, 2026
Duration
30m

Contact sales

By clicking submit, you agree to our Privacy Policy and Terms of Use, and consent to receive marketing emails from Pluralsight.
Table of Contents
  1. Challenge

    Introduction

    Background

    Welcome to the Store Checkout Toolkit Lab.

    You've just joined the engineering team of a small online store. The store sells notebooks, mugs, stickers, and the occasional Mystery Box. Business is growing fast … the codebase is not.

    Every time Marketing launches a promotion, discount logic gets copy-pasted across checkout, receipts, and sales reports. It works… until it doesn't.

    Last week, for the same product, three different systems reported three different prices:

    | Service | Price shown | |---------|-------------| | Checkout | EUR 9.00 | | Receipt | EUR 10.00 | | Sales report | EUR 8.50 |

    Same product. Three results. One very unhappy customer and one very confused finance team.

    Your mission: refactor this fragile system into a clean, reusable Python toolkit using functions, so every service agrees on the price and Marketing can change promotions without breaking half the store.

    No pressure 😅.

    --- ## What you'll build

    This lab takes you from duplicated discount math to a modular checkout pipeline.

    You will progressively move from copy-pasted formulas to structured, reusable code:

    • Extract one discount function used by checkout, receipts, and sales reports.
    • Parameterize the discount logic for regular, VIP, and clearance customers.
    • Compose small helper functions into a full order total (subtotal → discount → tax).
    • Return values from functions so each result can be reused, tested, and passed to the next step.

    Unlike a single homework script, real checkout systems are touched by many files, many teams, and many promotions. A small duplication today becomes three conflicting prices tomorrow.

    --- ## The three stages of the lab

    | Step | Theme | What you build | |------|-------|----------------| | 1 | Remove duplication | Extract apply_store_discount and wire checkout, receipt, and sales report to call it | | 2 | Flexible promotions | Upgrade to apply_discount(price, percent_off) for regular, VIP, and clearance tiers | | 3 | Checkout pipeline | Implement line_total, add_tax, and order_total — discount before tax |

    --- ## Three beginner mistakes

    Store code rarely breaks in only one way. This lab targets three common beginner habits:

    | Mistake | What goes wrong | What you'll do instead | |---------|-----------------|------------------------| | Copy-paste logic | Same formula in checkout, receipt, and report — prices drift apart | One function, many callers | | Hardcoded rules | 0.15 baked into every file — every new promo needs surgery | percent_off as a parameter | | Printing inside logic | print() in a discount function — hard to test and reuse | return the value; print only in demos |

    Understanding why these habits hurt maintainability is as important as getting the math right.

    --- ## More details

    Why duplicated formulas cause bugs

    Writing price * (1 - 0.15) in three places might feel faster, but it creates technical debt.

    Every copy is a future bug waiting to happen:

    • The Marketing team changes the rate, but someone forgets to update the receipt script.
    • The Finance team fixes the sales report, but checkout still uses the old formula.
    • A new engineer copies the pattern again, and now there are four sources of truth.
    What functions give you

    Functions solve a different problem than making code shorter. They give you:

    • One place to change business rules: update the discount once, not in five scripts.
    • Parameters: one function handles 10%, 20%, or 30% off without copy-paste variants.
    • Return values: compute a result, pass it to the next step, and test it in isolation.
    • Composition: build order_total from line_total, apply_discount, and add_tax.
    How the checkout pipeline works

    Checkout here is not one long script. It is a pipeline: define each step once, call it in the right order, and let orchestration glue the story together.

    Subtotal → discount → tax ## Core elements
    
    In this lab, you will work with:
    
    **The bug story**  
    Three services should show the same price, but they do not because the 15% discount formula was duplicated instead of shared.
    
    **`apply_store_discount`**  
    Step 1's single source of truth for the standard store discount. One function, three call sites.
    
    **Customer tiers**  
    Regular (10% off), VIP (20% off), and clearance (30% off). Step 2 replaces a hardcoded rate with a parameter.
    
    **The cart format**  
    Orders are lists of line items:
    
    ```python
    items = [{"qty": 2, "price": 12.50}, {"qty": 1, "price": 8.00}]
    

    The checkout pipeline
    The checkout flow follows this order: Subtotal → discount → tax. Each step is its own function; order_total orchestrates without repeating math.

    Processing order (important)
    Apply the discount before calculating tax. In this lab, tax is calculated on the discounted amount.

    Pre-written orchestration
    The run_step1, run_step2, run_step3, and receipt formatting code are already provided. You will focus on the core function logic.


    Learning objectives

    By the end of this lab, you should be able to:

    • Define reusable Python functions with def
    • Replace duplicated logic with a single function called from multiple places
    • Use parameters to make one function flexible for different inputs
    • Return values from functions and reuse them in later computations
    • Break a checkout flow into small functions with single responsibilities
    • Compose functions into a pipeline (order_totalline_total + apply_discount + add_tax)
    • Explain why discount must be applied before tax in this pipeline

    --- ## Lab structure

    You will work primarily inside the src/ directory.

    Each step contains guided TODO sections. Orchestrators, receipt demos, and run_step* output are already provided so you can focus on the function concepts.

    | File | Your focus | |------|------------| | src/step1_remove_duplication.py | Extract discount logic; connect checkout, receipt, and report | | src/step2_flexible_discounts.py | Parameterized apply_discount | | src/step3_checkout_pipeline.py | Line totals, tax, and full order_total |

    --- ## You're ready to begin

    Open src/step1_remove_duplication.py.

    Your first task: extract the duplicated 15% discount into apply_store_discount so checkout, receipts, and sales reports all return the same price for the same product.

    Let's begin!

    If you get stuck at any point, full reference implementations are provided in the solution/ folder in your file tree.

  2. Challenge

    Step 1 — Remove the discount duplication

    The situation

    The store applies a 15% discount in three places: checkout, printed receipt, and sales report.

    There is no shared function. Each team copy-pasted discount math straight into its own script:

    # checkout.py
    original_price = 10.00
    sale_price = original_price * (1 - 0.10)   # never updated from old promo
    
    # receipt.py
    original_price = 10.00
    sale_price = original_price              # discount step missing
    
    # report.py
    original_price = 10.00
    sale_price = original_price * (1 - 0.15)   # correct rate, still duplicated
    

    The Marketing team sent one email. Three teams pasted different versions. Nobody noticed until a customer complained.


    See the bug first

    Open src/step1_remove_duplication.py and run it as-is:

    python3 src/step1_remove_duplication.py
    

    The BEFORE block simulates those three scripts. They still use copy-pasted code and have no reusable function:

    === BEFORE refactor — copy-pasted code, no shared function ===
    Original price: EUR 10.00
    Checkout:       EUR 9.00
    Receipt:        EUR 10.00
    Sales report:   EUR 8.50
    
    Same product, three prices — three scripts, three copy-pastes.
    

    Scroll to the PRE-WRITTEN — Before refactor section. You'll see:

    • run_checkout_script
    • run_receipt_script
    • run_report_script
    • Each function has its own inline sale_price = ... line.

    Do not edit that block. It shows how things worked (badly) before you introduce functions.

    Below that, the TODO section is empty. That's where you build the refactor.


    What you'll build

    By the end of this step:

    • apply_store_discount(price) — the first shared discount function (replacing all that copy-paste)
    • checkout_price, receipt_price, and report_sale_price — thin wrappers that call it
    • Running the file again shows the AFTER block where all three services return EUR 8.50:
    === AFTER refactor — one function, three callers ===
    ...
    All three services agree — refactor complete.
    

    Your tasks

    You will work through 4 functions in order in src/step1_remove_duplication.py. ## Step complete

    When all four tasks pass Validate, run the experiment script using the following command:

    python3 src/step1_remove_duplication.py
    
    • BEFORE block still shows the old copy-pasted mess (unchanged)
    • AFTER block shows EUR 8.50 from all three refactored functions

    You can move now to Step 2: src/step2_flexible_discounts.py

  3. Challenge

    Step 2 — Create flexible promotions

    The situation

    Your Step 1 refactor worked. For about five minutes.

    Marketing now wants different discounts by customer type:

    | Customer type | Discount | |---------------|----------| | Regular | 10% off | | VIP | 20% off | | Clearance | 30% off |

    apply_store_discount only knows 15%. The quick fix — the one every tired team reaches for — is to copy the function again:

    def apply_regular_discount(price):
        return round(price * (1 - 0.10), 2)
    
    def apply_vip_discount(price):
        return round(price * (1 - 0.20), 2)
    
    def apply_clearance_discount(price):
        return round(price * (1 - 0.30), 2)
    

    Three promos, three functions. Sound familiar? You just solved duplication in Step 1. Don't recreate it with a different number.


    See the problem first

    Open src/step2_flexible_discounts.py and run it as-is:

    python3 src/step2_flexible_discounts.py
    

    The BEFORE block shows the three-function approach still working:

    === BEFORE refactor — one hardcoded function per promo ===
    Base price: EUR 50.00
      regular    EUR 45.00
      vip        EUR 40.00
      clearance  EUR 35.00
    
    Three promos, three functions — what happens when Marketing adds a fourth?
    

    Scroll to PRE-WRITTEN — Before refactor. You'll see:

    • apply_regular_discount
    • apply_vip_discount
    • apply_clearance_discount

    Each function uses the same pattern with a different hardcoded rate. Do not edit that block.

    Below it, apply_discount is empty. That's your upgrade.


    What you'll build

    By the end of this step:

    • One function, apply_discount(price, percent_off), that supports any discount percentage
    • A returned discounted price (rounded to cents)
    • No print inside the function

    The run_step2() function reuses apply_discount for all three tiers on a EUR 50.00 base price:

    === AFTER refactor — one function, any percent_off ===
    Base price: EUR 50.00
      regular    EUR 45.00
      vip        EUR 40.00
      clearance  EUR 35.00
    
    One function handles every tier — add a fourth promo without a new function.
    

    Note: Step 1 used apply_store_discount (fixed 15%). Step 2 introduces apply_discount (flexible). That's intentional because you're evolving the design, not starting over.


    Your task

    You will complete 1 function in src/step2_flexible_discounts.py, then Validate (see tests text).

    --- ## Step complete

    When Task 5 passes Validate, run the experiment script using the following command:

    python3 src/step2_flexible_discounts.py
    
    • BEFORE block still shows three separate hardcoded functions (unchanged)
    • AFTER block prints regular / vip / clearance prices via one apply_discount

    You can move now to Step 3: src/step3_checkout_pipeline.py

  4. Challenge

    Step 3 — Build the checkout pipeline

    The situation

    Marketing wants a full checkout system for every order:

    • Multiple items in the cart
    • Customer-specific discount (from Step 2)
    • Tax on the final amount
    • One total everyone agrees on

    The old approach? One long script with every calculation inline:

    # old checkout.py — everything in one block
    subtotal = 0.0
    for item in items:
        subtotal = subtotal + item["qty"] * item["price"]
    after_discount = subtotal * (1 - percent_off / 100)
    final = after_discount * (1 + tax_rate)
    

    It produces a number. But you can't reuse line_total on the receipt, test the discount logic alone, or easily spot a workflow bug such as applying tax before the discount.


    See the problem first

    Open src/step3_checkout_pipeline.py and run it as-is:

    python3 src/step3_checkout_pipeline.py
    

    The BEFORE block runs run_checkout_inline, where all math happens in one function:

    === BEFORE refactor — one script, all math inline ===
      subtotal = sum(qty * price)
      after_discount = subtotal * (1 - percent_off / 100)
      final = after_discount * (1 + tax_rate)
    
    Cart total: EUR 32.08
    
    It works once — but try reusing 'discount logic' on the receipt and report.
    

    Scroll to PRE-WRITTEN — Before refactor. Do not edit that block. It shows the monolithic version.

    Below it, three empty functions wait for you: line_total, add_tax, order_total.


    Input format

    Every cart is a list of line items:

    items = [{"qty": 2, "price": 12.50}, {"qty": 1, "price": 8.00}]
    
    • qty — how many units
    • price — unit price in euros

    Processing rules

    Each function owns one step. order_total calls them in this order:

    | Order | Step | Function | What it does | |-------|------|----------|----------------| | 1 | Subtotal | line_total(qty, price) per item, then sum | 2×12.50 + 1×8.00 = 33.00 | | 2 | Discount | apply_discount(subtotal, percent_off) | 33.00 with 10% off → 29.70 | | 3 | Tax | add_tax(discounted_amount, tax_rate) | 29.70 with 8% tax → 32.08 |

    Important:

    Make sure to apply the discount before calculating tax. In this lab, tax is calculated on the discounted amount, not the original subtotal.

    Worked example (10% off, 8% tax):

    Line 1:  2 × EUR 12.50 = EUR 25.00
    Line 2:  1 × EUR  8.00 = EUR  8.00
             -------------------------
    Subtotal:                  EUR 33.00
    Discount (10%):            EUR 29.70
    Tax (8% of 29.70):         EUR  2.38
    TOTAL:                     EUR 32.08
    

    What you'll build

    By the end of this step:

    • line_total(quantity, unit_price) — one line item's cost
    • add_tax(amount, tax_rate): calculates tax on an amount where 0.08 means 8%.
    • order_total(items, percent_off, tax_rate): orchestrates the full pipeline
    • apply_discount is imported from Step 2 — not reimplemented
    • run_step3(): prints a full receipt via format_receipt (pre-written)
    === AFTER refactor — small functions, clear pipeline ===
    --- Store Receipt ---
      2 x EUR 12.50 = EUR 25.00
      1 x EUR 8.00 = EUR 8.00
    Subtotal:   EUR 33.00
    Discount:   10% off -> EUR 29.70
    Tax:        EUR 2.38
    TOTAL:      EUR 32.08
    

    Your tasks

    You will work through 3 functions in order in src/step3_checkout_pipeline.py, validating after each (see tests text).

    --- ## Validate

    After each task:

    pytest tests/test_step3_pipeline.py -v
    

    LMS (one task at a time):

    python scripts/validate.py tests/test_step3_pipeline.py -k "test_line_total_matches_reference"
    python scripts/validate.py tests/test_step3_pipeline.py -k "test_add_tax_matches_reference"
    python scripts/validate.py tests/test_step3_pipeline.py -k "test_order_total_matches_reference"
    

    Run the full script when done:

    python src/step3_checkout_pipeline.py
    

    The AFTER block should print the receipt with TOTAL: EUR 32.08.


    Lab complete

    When all three Step 3 tasks pass Validate, run the experiment script using the following command:

    python3 src/step3_checkout_pipeline.py
    
    • BEFORE block still shows inline run_checkout_inline (unchanged)
    • AFTER block prints a full receipt with TOTAL: EUR 32.08
    • order_total calls line_total, apply_discount, and add_tax — no inline pipeline math
    • Discount is applied before tax

    The lab is finished. When Marketing launches the next promotion, learners update one function — not five scripts.

About the author

Marc is a Senior Data Scientist with a solid foundation in Communication and Computer Engineering and holds a Master's degree in AI and Deep Learning from one of France's leading universities. His career is driven by a deep passion for data science and artificial intelligence, combining technical expertise with innovative thinking to deliver impactful solutions.

Real skill practice before real-world application

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Learn by doing

Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.

Follow your guide

All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.

Turn time into mastery

On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.

Get started with Pluralsight