diff --git a/python-modules-packages/README.md b/python-modules-packages/README.md new file mode 100644 index 0000000000..eb44798fea --- /dev/null +++ b/python-modules-packages/README.md @@ -0,0 +1,55 @@ +# Python Modules and Packages – An Introduction + +This folder provides the code examples for the Real Python tutorial [Python Modules and Packages – An Introduction](https://realpython.com/python-modules-packages/). + +## Setup + +The examples use only the standard library, so there's nothing to install. They were tested on Python 3.14, which is the version the tutorial's output reflects. On older versions, some output differs. For example, `dir()` lists `'__annotations__'` before Python 3.14, and a namespace package's repr omits its `from [...]` path list before Python 3.12. + +## Usage + +The tutorial changes `mod.py`, `pkg/__init__.py`, and `pkg/mod1.py` as it goes, so each stage lives in its own folder: + +| Folder | Section | Contents | +| --- | --- | --- | +| `module_basics/` | Python Modules: Overview | `mod.py`, which only defines objects | +| `module_as_script/` | Executing a Module as a Script | `mod.py`, which prints output every time it runs | +| `main_guard/` | Executing a Module as a Script | `mod.py` and `fact.py`, which check `__name__` | +| `module_reload/` | Reloading a Module | `mod.py`, which prints when it's loaded | +| `package_basics/` | Python Packages | `pkg/` with `mod1.py` and `mod2.py` and no `__init__.py` | +| `package_init_data/` | Package Initialization | `pkg/__init__.py` defining the package-level list `A` | +| `package_init_imports/` | Package Initialization | `pkg/__init__.py` importing `mod1` and `mod2` | +| `import_star/` | Importing `*` From a Package | `pkg/` with four modules and no `__init__.py` | +| `import_star_all/` | Importing `*` From a Package | `pkg/` with `__all__` in `__init__.py` and `mod1.py` | +| `subpackages_absolute/` | Subpackages | `pkg/sub_pkg1/` and `pkg/sub_pkg2/`, with `mod3.py` using an absolute import | +| `subpackages_relative/` | Subpackages | The same tree, with `mod3.py` using relative imports | + +Change into a folder before you start the interpreter, so that `mod` or `pkg` is importable from the current directory. For example: + +```console +$ cd main_guard/ +$ python mod.py +Executing as standalone script +If Comrade Napoleon says it, it must be right. +[100, 200, 300] +arg = quux +<__main__.Foo object at 0x7f1ddeba0c20> + +$ python fact.py 6 +720 +``` + +```console +$ cd subpackages_relative/ +$ python +>>> from pkg.sub_pkg2 import mod3 + +[mod1] foo() +``` + +Start a fresh interpreter session for each example. Python loads a module only once per session, and a submodule that you've already imported shows up in the output of `from pkg import *`. + +The code is formatted to the repository's style, so it differs slightly from the tutorial. It uses double quotes, and the `if __name__ == "__main__":` lines don't have parentheses. Some import lines carry `# noqa` comments, because they deliberately show patterns that a linter flags: + +- `package_init_imports/pkg/__init__.py` imports two modules on one line after a `print()` call. +- `mod3.py` in both `subpackages_*/` folders imports at the bottom of the file, after the definitions. diff --git a/python-modules-packages/import_star/pkg/mod1.py b/python-modules-packages/import_star/pkg/mod1.py new file mode 100644 index 0000000000..a4faab6ba4 --- /dev/null +++ b/python-modules-packages/import_star/pkg/mod1.py @@ -0,0 +1,6 @@ +def foo(): + print("[mod1] foo()") + + +class Foo: + pass diff --git a/python-modules-packages/import_star/pkg/mod2.py b/python-modules-packages/import_star/pkg/mod2.py new file mode 100644 index 0000000000..535b33fd52 --- /dev/null +++ b/python-modules-packages/import_star/pkg/mod2.py @@ -0,0 +1,6 @@ +def bar(): + print("[mod2] bar()") + + +class Bar: + pass diff --git a/python-modules-packages/import_star/pkg/mod3.py b/python-modules-packages/import_star/pkg/mod3.py new file mode 100644 index 0000000000..56d9ba41cf --- /dev/null +++ b/python-modules-packages/import_star/pkg/mod3.py @@ -0,0 +1,6 @@ +def baz(): + print("[mod3] baz()") + + +class Baz: + pass diff --git a/python-modules-packages/import_star/pkg/mod4.py b/python-modules-packages/import_star/pkg/mod4.py new file mode 100644 index 0000000000..7314d79722 --- /dev/null +++ b/python-modules-packages/import_star/pkg/mod4.py @@ -0,0 +1,6 @@ +def qux(): + print("[mod4] qux()") + + +class Qux: + pass diff --git a/python-modules-packages/import_star_all/pkg/__init__.py b/python-modules-packages/import_star_all/pkg/__init__.py new file mode 100644 index 0000000000..ccda79be9d --- /dev/null +++ b/python-modules-packages/import_star_all/pkg/__init__.py @@ -0,0 +1 @@ +__all__ = ["mod1", "mod2", "mod3", "mod4"] diff --git a/python-modules-packages/import_star_all/pkg/mod1.py b/python-modules-packages/import_star_all/pkg/mod1.py new file mode 100644 index 0000000000..e1cb85da35 --- /dev/null +++ b/python-modules-packages/import_star_all/pkg/mod1.py @@ -0,0 +1,9 @@ +__all__ = ["foo"] + + +def foo(): + print("[mod1] foo()") + + +class Foo: + pass diff --git a/python-modules-packages/import_star_all/pkg/mod2.py b/python-modules-packages/import_star_all/pkg/mod2.py new file mode 100644 index 0000000000..535b33fd52 --- /dev/null +++ b/python-modules-packages/import_star_all/pkg/mod2.py @@ -0,0 +1,6 @@ +def bar(): + print("[mod2] bar()") + + +class Bar: + pass diff --git a/python-modules-packages/import_star_all/pkg/mod3.py b/python-modules-packages/import_star_all/pkg/mod3.py new file mode 100644 index 0000000000..56d9ba41cf --- /dev/null +++ b/python-modules-packages/import_star_all/pkg/mod3.py @@ -0,0 +1,6 @@ +def baz(): + print("[mod3] baz()") + + +class Baz: + pass diff --git a/python-modules-packages/import_star_all/pkg/mod4.py b/python-modules-packages/import_star_all/pkg/mod4.py new file mode 100644 index 0000000000..7314d79722 --- /dev/null +++ b/python-modules-packages/import_star_all/pkg/mod4.py @@ -0,0 +1,6 @@ +def qux(): + print("[mod4] qux()") + + +class Qux: + pass diff --git a/python-modules-packages/main_guard/fact.py b/python-modules-packages/main_guard/fact.py new file mode 100644 index 0000000000..e798d6b95f --- /dev/null +++ b/python-modules-packages/main_guard/fact.py @@ -0,0 +1,9 @@ +def fact(n): + return 1 if n == 1 else n * fact(n - 1) + + +if __name__ == "__main__": + import sys + + if len(sys.argv) > 1: + print(fact(int(sys.argv[1]))) diff --git a/python-modules-packages/main_guard/mod.py b/python-modules-packages/main_guard/mod.py new file mode 100644 index 0000000000..f681480c6e --- /dev/null +++ b/python-modules-packages/main_guard/mod.py @@ -0,0 +1,19 @@ +s = "If Comrade Napoleon says it, it must be right." +a = [100, 200, 300] + + +def foo(arg): + print(f"arg = {arg}") + + +class Foo: + pass + + +if __name__ == "__main__": + print("Executing as standalone script") + print(s) + print(a) + foo("quux") + x = Foo() + print(x) diff --git a/python-modules-packages/module_as_script/mod.py b/python-modules-packages/module_as_script/mod.py new file mode 100644 index 0000000000..44277539df --- /dev/null +++ b/python-modules-packages/module_as_script/mod.py @@ -0,0 +1,17 @@ +s = "If Comrade Napoleon says it, it must be right." +a = [100, 200, 300] + + +def foo(arg): + print(f"arg = {arg}") + + +class Foo: + pass + + +print(s) +print(a) +foo("quux") +x = Foo() +print(x) diff --git a/python-modules-packages/module_basics/mod.py b/python-modules-packages/module_basics/mod.py new file mode 100644 index 0000000000..0cba0efa88 --- /dev/null +++ b/python-modules-packages/module_basics/mod.py @@ -0,0 +1,10 @@ +s = "If Comrade Napoleon says it, it must be right." +a = [100, 200, 300] + + +def foo(arg): + print(f"arg = {arg}") + + +class Foo: + pass diff --git a/python-modules-packages/module_reload/mod.py b/python-modules-packages/module_reload/mod.py new file mode 100644 index 0000000000..0690da3be6 --- /dev/null +++ b/python-modules-packages/module_reload/mod.py @@ -0,0 +1,2 @@ +a = [100, 200, 300] +print("a =", a) diff --git a/python-modules-packages/package_basics/pkg/mod1.py b/python-modules-packages/package_basics/pkg/mod1.py new file mode 100644 index 0000000000..a4faab6ba4 --- /dev/null +++ b/python-modules-packages/package_basics/pkg/mod1.py @@ -0,0 +1,6 @@ +def foo(): + print("[mod1] foo()") + + +class Foo: + pass diff --git a/python-modules-packages/package_basics/pkg/mod2.py b/python-modules-packages/package_basics/pkg/mod2.py new file mode 100644 index 0000000000..535b33fd52 --- /dev/null +++ b/python-modules-packages/package_basics/pkg/mod2.py @@ -0,0 +1,6 @@ +def bar(): + print("[mod2] bar()") + + +class Bar: + pass diff --git a/python-modules-packages/package_init_data/pkg/__init__.py b/python-modules-packages/package_init_data/pkg/__init__.py new file mode 100644 index 0000000000..9ff51f607b --- /dev/null +++ b/python-modules-packages/package_init_data/pkg/__init__.py @@ -0,0 +1,2 @@ +print(f"Invoking __init__.py for {__name__}") +A = ["quux", "corge", "grault"] diff --git a/python-modules-packages/package_init_data/pkg/mod1.py b/python-modules-packages/package_init_data/pkg/mod1.py new file mode 100644 index 0000000000..c4542d54f7 --- /dev/null +++ b/python-modules-packages/package_init_data/pkg/mod1.py @@ -0,0 +1,8 @@ +def foo(): + from pkg import A + + print("[mod1] foo() / A = ", A) + + +class Foo: + pass diff --git a/python-modules-packages/package_init_data/pkg/mod2.py b/python-modules-packages/package_init_data/pkg/mod2.py new file mode 100644 index 0000000000..535b33fd52 --- /dev/null +++ b/python-modules-packages/package_init_data/pkg/mod2.py @@ -0,0 +1,6 @@ +def bar(): + print("[mod2] bar()") + + +class Bar: + pass diff --git a/python-modules-packages/package_init_imports/pkg/__init__.py b/python-modules-packages/package_init_imports/pkg/__init__.py new file mode 100644 index 0000000000..83d9d6a845 --- /dev/null +++ b/python-modules-packages/package_init_imports/pkg/__init__.py @@ -0,0 +1,2 @@ +print(f"Invoking __init__.py for {__name__}") +import pkg.mod1, pkg.mod2 # noqa: E401, E402, F401 diff --git a/python-modules-packages/package_init_imports/pkg/mod1.py b/python-modules-packages/package_init_imports/pkg/mod1.py new file mode 100644 index 0000000000..a4faab6ba4 --- /dev/null +++ b/python-modules-packages/package_init_imports/pkg/mod1.py @@ -0,0 +1,6 @@ +def foo(): + print("[mod1] foo()") + + +class Foo: + pass diff --git a/python-modules-packages/package_init_imports/pkg/mod2.py b/python-modules-packages/package_init_imports/pkg/mod2.py new file mode 100644 index 0000000000..535b33fd52 --- /dev/null +++ b/python-modules-packages/package_init_imports/pkg/mod2.py @@ -0,0 +1,6 @@ +def bar(): + print("[mod2] bar()") + + +class Bar: + pass diff --git a/python-modules-packages/subpackages_absolute/pkg/sub_pkg1/mod1.py b/python-modules-packages/subpackages_absolute/pkg/sub_pkg1/mod1.py new file mode 100644 index 0000000000..a4faab6ba4 --- /dev/null +++ b/python-modules-packages/subpackages_absolute/pkg/sub_pkg1/mod1.py @@ -0,0 +1,6 @@ +def foo(): + print("[mod1] foo()") + + +class Foo: + pass diff --git a/python-modules-packages/subpackages_absolute/pkg/sub_pkg1/mod2.py b/python-modules-packages/subpackages_absolute/pkg/sub_pkg1/mod2.py new file mode 100644 index 0000000000..535b33fd52 --- /dev/null +++ b/python-modules-packages/subpackages_absolute/pkg/sub_pkg1/mod2.py @@ -0,0 +1,6 @@ +def bar(): + print("[mod2] bar()") + + +class Bar: + pass diff --git a/python-modules-packages/subpackages_absolute/pkg/sub_pkg2/mod3.py b/python-modules-packages/subpackages_absolute/pkg/sub_pkg2/mod3.py new file mode 100644 index 0000000000..8084c8223a --- /dev/null +++ b/python-modules-packages/subpackages_absolute/pkg/sub_pkg2/mod3.py @@ -0,0 +1,11 @@ +def baz(): + print("[mod3] baz()") + + +class Baz: + pass + + +from pkg.sub_pkg1.mod1 import foo # noqa: E402 + +foo() diff --git a/python-modules-packages/subpackages_absolute/pkg/sub_pkg2/mod4.py b/python-modules-packages/subpackages_absolute/pkg/sub_pkg2/mod4.py new file mode 100644 index 0000000000..7314d79722 --- /dev/null +++ b/python-modules-packages/subpackages_absolute/pkg/sub_pkg2/mod4.py @@ -0,0 +1,6 @@ +def qux(): + print("[mod4] qux()") + + +class Qux: + pass diff --git a/python-modules-packages/subpackages_relative/pkg/sub_pkg1/mod1.py b/python-modules-packages/subpackages_relative/pkg/sub_pkg1/mod1.py new file mode 100644 index 0000000000..a4faab6ba4 --- /dev/null +++ b/python-modules-packages/subpackages_relative/pkg/sub_pkg1/mod1.py @@ -0,0 +1,6 @@ +def foo(): + print("[mod1] foo()") + + +class Foo: + pass diff --git a/python-modules-packages/subpackages_relative/pkg/sub_pkg1/mod2.py b/python-modules-packages/subpackages_relative/pkg/sub_pkg1/mod2.py new file mode 100644 index 0000000000..535b33fd52 --- /dev/null +++ b/python-modules-packages/subpackages_relative/pkg/sub_pkg1/mod2.py @@ -0,0 +1,6 @@ +def bar(): + print("[mod2] bar()") + + +class Bar: + pass diff --git a/python-modules-packages/subpackages_relative/pkg/sub_pkg2/mod3.py b/python-modules-packages/subpackages_relative/pkg/sub_pkg2/mod3.py new file mode 100644 index 0000000000..4220ce505e --- /dev/null +++ b/python-modules-packages/subpackages_relative/pkg/sub_pkg2/mod3.py @@ -0,0 +1,15 @@ +def baz(): + print("[mod3] baz()") + + +class Baz: + pass + + +from .. import sub_pkg1 # noqa: E402 + +print(sub_pkg1) + +from ..sub_pkg1.mod1 import foo # noqa: E402 + +foo() diff --git a/python-modules-packages/subpackages_relative/pkg/sub_pkg2/mod4.py b/python-modules-packages/subpackages_relative/pkg/sub_pkg2/mod4.py new file mode 100644 index 0000000000..7314d79722 --- /dev/null +++ b/python-modules-packages/subpackages_relative/pkg/sub_pkg2/mod4.py @@ -0,0 +1,6 @@ +def qux(): + print("[mod4] qux()") + + +class Qux: + pass