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, andpyproject.tomlare 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
2items at price25.0, labeledLine total:. - Task-2: print that line total with a
10percent discount applied, labeledAfter 10 percent off:.
Keep the store/ package folder next to your main script:
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
# __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"]
# 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
# 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)
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
3units ofNotebookat price40. - Task-2: print the summary for
1unit ofPenat price15.
Put those two print calls at the BOTTOM of the file for now, with no guard. Running the file prints both lines:
File 2, s12_practice02_order_report.py. This file wants one thing from your module, the function, and nothing else.
- Task-3: import
order_summaryfrom file 1, then print a report line for2units ofMarkerat price15, in the formReport: 2 x Marker = 30.
Now see the bug. Run file 2 while file 1 still has no guard:
- 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:
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
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))
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.
Practice: Standard Library Essentials Next: Practice: Classes and OOP Basics