Build a package, import it, use __all__
The example creates the whole shop package on disk (Path(...).mkdir() makes a folder, write_text fills a file; Topic 7.6 teaches pathlib), then imports it. Notice that __init__.py prints when it runs, and that the star import brings in exactly the names in __all__. hasattr(shop, "__path__") asks "does this object have a name __path__?" (only packages do). The exec line runs one line of text as Python code and namespace collects the names it creates. You will rarely need exec: here it only lets us inspect what a star import brings in.
A package is a folder of modules that you import as one unit. Its __init__.py runs on import and decides what the package shows to the outside, absolute imports name the full path from the top, relative imports use dots, and circular imports are fixed by changing who imports whom.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 5 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Create a package zoo: a folder zoo with an empty __init__.py, and a module zoo/cat.py that contains SOUND = "meow". Then write the code that imports cat from zoo and prints cat.SOUND.
Change the __init__.py of your zoo package so that SOUND is available directly. After your change, from zoo import SOUND must work.
Write the relative-import line that zoo/dog.py would use to import SOUND from its sibling cat.py.
Explain it without notes
What is a package, and what does __init__.py do?
What is the difference between absolute and relative imports? When does each fail?
What is __all__ for?
What causes a circular import error, and how do you fix it?
Expected output
shop/__init__.py ran
package name: shop | is a package: True
total: 66.0
shop.tax.RATE = 0.1
star import gave: ['VERSION', 'total']