Skip to content

Practice: Virtual Environments and Packaging

View practice code on GitHub Get the Video Course

From the lesson

Practice problems for Section 12 Concepts. Build each yourself first, then expand the solution to check.

Two practice problems on the packaging skill you can actually run: building and importing your own package, and guarding "run-it-directly" code with the __main__ guard. Build each yourself, then check python-practice/solutions.

These problems continue the online store story. In the section you built a number_utils package. Here you build a small store package of pricing helpers and a self-testing order module, the same way you would organize code in a real project.

Note: virtual environments, pip, and pyproject.toml are terminal/config skills, so they are not practiced as runnable Python here. These two problems drill the parts you write and run in Python: your own package and the __main__ guard.

Practice Problem-01: build and import your own package

Concepts: a package (a folder of modules) and its __init__.py front door, a module of functions, __all__, importing your own package.

Build a package named store for an online store. Inside it, a module pricing.py holds two functions: line_total(price, quantity) returns price * quantity, and apply_discount(total, percent) returns the total with that percent taken off. The package's __init__.py is its front door: it brings both functions out so a main script can import them straight from store, and it lists both names in __all__. Then write a main script that imports line_total and apply_discount from store, and:

  • Task-1: print the line total for 2 items at price 25.0, labeled Line total:.
  • Task-2: print that line total with a 10 percent discount applied, labeled After 10 percent off:.
Expected output
Line total: 50.0
After 10 percent off: 45.0

Keep the store/ package folder next to your main script:

folder layout
store/
    __init__.py     # the front door: brings both functions out, lists them in __all__
    pricing.py      # the two functions
s12_practice01_build_and_import_package.py   # imports and uses the package

Warning

store/__init__.py is the package's front door. The line in it that imports both functions from store.pricing is what lets your main script import them straight from store. __all__ only decides what from store import * brings in. Run the main script from the folder that holds store/, so Python can find the package next to it.

Need a hint?

Open the front door: store/__init__.py does from store.pricing import line_total, apply_discount, which is what lets your main script say from store import line_total, apply_discount. Add __all__ listing both names, as the task asks. For the discount, work out that percent of the total (total * percent / 100) and take it off. Call line_total first, then feed its result into apply_discount.

Show the solution
store/__init__.py
# __init__.py is the store package's front door. Python runs it when store is imported.
# It brings the functions out, so other files can do: from store import line_total, apply_discount
from store.pricing import line_total, apply_discount

# __all__ lists what "from store import *" hands out. Named imports are not affected.
__all__ = ["line_total", "apply_discount"]
store/pricing.py
# A module inside the "store" package. It holds two small pricing functions.

def line_total(price, quantity):
    return price * quantity


def apply_discount(total, percent):
    discount = total * percent / 100
    return total - discount
s12_practice01_sol_build_and_import_package.py
# Import from your OWN package (the store/ folder next to this file)
from store import line_total, apply_discount

# Task-1: print the line total for 2 items at price 25.0
total = line_total(25.0, 2)
print("Line total:", total)

# Task-2: print that line total with a 10 percent discount applied
discounted = apply_discount(total, 10)
print("After 10 percent off:", discounted)

View the full solution on GitHub

Practice Problem-02: run-it-directly self-test with the __main__ guard

Concepts: a function that returns a value, the special name __name__, an if __name__ == "__main__" guard, and what changes when another file IMPORTS your module instead of running it.

This one takes two files, the same shape as Step-03: a module, and a second file that imports it.

File 1, s12_practice02_main_guard_self_test.py. Write a function order_summary(product, quantity, price) that returns the text <quantity> x <product> = <total>, where total is quantity * price. Then give it a self-test that prints two summaries:

  • Task-1: print the summary for 3 units of Notebook at price 40.
  • Task-2: print the summary for 1 unit of Pen at price 15.

Put those two print calls at the BOTTOM of the file for now, with no guard. Running the file prints both lines:

Expected output
3 x Notebook = 120
1 x Pen = 15

File 2, s12_practice02_order_report.py. This file wants one thing from your module, the function, and nothing else.

  • Task-3: import order_summary from file 1, then print a report line for 2 units of Marker at price 15, in the form Report: 2 x Marker = 30.

Now see the bug. Run file 2 while file 1 still has no guard:

Example run: file 2 BEFORE the guard
3 x Notebook = 120
1 x Pen = 15
Report: 2 x Marker = 30
  • Task-4: you never asked for those first two lines. Work out why they appeared.
  • Task-5: put file 1's two self-test calls behind an if __name__ == "__main__" guard, then run file 2 again. Only your own line should be left:
Example run: file 2 AFTER the guard
Report: 2 x Marker = 30

Running file 1 directly must still print both summaries. One file, both jobs.

Tip

Stuck on Task-4? Open the hint below. This is the same thing Step-03 showed you with app.py and runner.py.

Need a hint?

Make order_summary RETURN an f-string like f"{quantity} x {product} = {total}" rather than printing it, so the second file can use the text however it likes. Leave the two calls bare at the bottom at first and run the second file: importing a module runs every top-level line in it, which is exactly why the self-test fires uninvited. Then wrap those two calls in if __name__ == "__main__":, which is true only when you run that file directly.

Show the solution
s12_practice02_sol_main_guard_self_test.py
def order_summary(product, quantity, price):
    total = quantity * price
    return f"{quantity} x {product} = {total}"


# Task-5 (added last): the guard. Without it, the two lines below run on IMPORT too, which is
# the bug s12_practice02_sol_order_report.py is there to show you.
if __name__ == "__main__":
    # Task-1: summary for 3 units of "Notebook" at price 40
    print(order_summary("Notebook", 3, 40))
    # Task-2: summary for 1 unit of "Pen" at price 15
    print(order_summary("Pen", 1, 15))
s12_practice02_sol_order_report.py
# Task-3: import from the module you wrote, then use it
from s12_practice02_sol_main_guard_self_test import order_summary

print("Report:", order_summary("Marker", 2, 15))

View the full solution on GitHub

Finished this section?

Check your work against the solutions above, then head back to the Section 12 lesson.

Prefer to learn by watching?

The full video course teaches every concept on screen and builds the projects with you, step by step.

Get the Video Course

Practice: Standard Library Essentials Next: Practice: Classes and OOP Basics

🎉 New Course
Python for Absolute Beginners
$15.99 $84.99 81% OFF
Get the Video Course