Module, Pakete und Standardbibliothek
Track Python · PCAP-Fundament · ca. 55 Min.
Worum es geht
In JS/TS importierst du Dateien über Pfade und installierst Pakete mit npm. Python hat dieselben Bausteine, aber andere Regeln: Ein Modul (module) ist einfach eine .py-Datei, ein Paket (package) ein Ordner voller Module, und es gibt kein export. Was auf Modulebene steht, lässt sich importieren. Dazu kommen drei Eigenheiten, die in der PCAP gerne abgefragt werden: Ein Modul läuft pro Programmlauf nur einmal, __name__ verrät, ob eine Datei gestartet oder importiert wurde, und from m import * bringt manchmal mehr Namen mit, als man denkt. Außerdem lernst du die Standardbibliothek (standard library) kennen, die in Python ersetzt, wofür du in Node oft ein npm-Paket nimmst.
Ablauf: erst die Übersetzung JS/TS nach Python, dann fünf kleine Schritte mit lauffähigem Code, dann fünf Übungen und eine lokale Zusatzaufgabe für venv und pip.
Von JS/TS her gedacht
| Thema | JS/TS | Python |
|---|---|---|
| Datei als Baustein | ES-Modul (.js, .ts) |
Modul (.py), Name = Dateiname ohne .py |
| Was ist importierbar | nur, was mit export markiert ist |
jeder Name auf Modulebene |
| Ordner als Baustein | Ordner mit index.js (Konvention) |
Paket: Ordner mit __init__.py |
| Import mit Umbenennung | import { sqrt as wurzel } from "math" |
from math import sqrt as wurzel |
| Relativer Import | import x from "./x" |
from . import x (nur innerhalb von Paketen) |
| Mehrfach importiert | Modul läuft einmal (Cache) | Modul läuft einmal (sys.modules) |
| Startcode nur beim direkten Start | if (require.main === module) (CommonJS) |
if __name__ == "__main__": |
| Pakete installieren | npm install axios |
pip install requests |
| Isolierte Umgebung | node_modules pro Projekt |
python -m venv .venv |
| Abhängigkeiten festhalten | package.json |
requirements.txt oder pyproject.toml |
Beide Sprachen führen ein Modul nur einmal aus. Python merkt sich geladene Module in sys.modules, ein Dictionary von Modulname nach Modulobjekt.
Konzept in kleinen Schritten
Schritt 1: Import-Varianten
Es gibt fünf Schreibweisen (Quelle: Glossar):
Die fünfte, from math import * (Stern-Import, star import), kommt in Schritt 4. Sie gilt als schlechter Stil, weil Namen kollidieren können.
Schritt 2: Ein Modul läuft nur einmal, sys.path und sys.modules
Wo sucht Python ein Modul? In sys.path, einer Liste von Ordnern. Das Verzeichnis des Startskripts steht vorne. Das probieren wir aus: Wir legen im Browser eine kleine Datei hallo.py an, setzen ihren Ordner vorne in sys.path und importieren sie zweimal.
Erwartete Ausgabe: Die zwei print-Zeilen aus hallo.py erscheinen einmal, danach hi, True, True. Drei Dinge siehst du hier:
- Der zweite
import halloholt das Modul aussys.modules. Der Code in der Datei läuft nicht noch einmal. - Beim Import ist
__name__der Modulname (hallo), nicht"__main__". - Führst du diese Zelle ein zweites Mal aus, bleibt
halloim Cache. Dieprint-Zeilen aushallo.pykommen dann nicht mehr. Das ist derselbe Effekt.
Schritt 3: __name__ und der Startcode
Läuft eine Datei direkt (python tool.py), ist __name__ gleich "__main__". Wird sie importiert, ist es der Modulname. Darum der Standard für Startcode:
runpy.run_path(..., run_name="__main__") startet die Datei so, als hättest du python tool.py getippt. Erwartete Ausgabe: erst importiert, bisher keine Ausgabe, dann Start. Die Zeile importlib.invalidate_caches() ist nötig, weil Python den Inhalt eines Ordners zwischenspeichert: Eine Datei, die erst zur Laufzeit entsteht, wird sonst unter Umständen nicht gefunden (ModuleNotFoundError). Ohne den Guard (if __name__ == ...) würde haupt() schon beim import tool laufen. Das ist der JS-Gedanke “ein Import soll keine Nebenwirkung haben”, nur hier explizit.
Schritt 4: Pakete, relative Imports und der Stern-Import
Ein Paket ist ein Ordner mit __init__.py. Die Datei läuft beim Import des Pakets und darf leer sein. Seit Python 3.3 funktionieren auch Ordner ohne diese Datei (Namespace-Pakete, namespace packages). Die klassische Variante bleibt Prüfungsstoff.
from .preis import brutto ist ein relativer Import (relative import): Der Punkt heißt “im selben Paket”. from . import x meint das gleiche Paket, from .. import y ein Paket höher. Relative Imports funktionieren nur innerhalb von Paketen, nicht in einer Datei, die du direkt startest.
Nun zum Stern-Import. from m import * holt alle “öffentlichen” Namen, also alle ohne führenden Unterstrich. Hat das Modul eine Liste __all__, zählen nur die dort genannten Namen. Eine Falle: Auch ein im Modul importiertes Modul (import math im Modul) ist ein Name ohne Unterstrich und kommt mit.
Weitere Modulattribute aus dem Glossar: __file__ (Pfad), __doc__ (Docstring), __path__ (bei Paketen), __all__. __pycache__ ist der Ordner, in dem Python kompilierten Bytecode (.pyc) ablegt. dir(obj) listet die Namen eines Objekts, help(obj) zeigt die Dokumentation.
Schritt 5: Standardbibliothek, venv und pip
Die Standardbibliothek liefert viel mit, ohne Installation. Die Liste aus dem Glossar:
math:pi,e,sqrt,ceil,floor,trunc,factorial,hypot,sin,cos,log,pow.random:random(),randrange(a, b),randint(a, b)(Ende inklusive),choice(seq),sample(seq, k),shuffle(liste),seed(n)für reproduzierbare Zufallszahlen.platform:platform(),system(),machine(),processor(),version(),python_version(),python_implementation().osundsys: Betriebssystem, Verzeichnisse, Pfade,sys.argv,sys.exit(),sys.path.datetime,time,calendar,copy,json,collections(Counter,defaultdict,deque),itertools,functools.
randint(1, 6) kann die 6 liefern, randrange(1, 6) nie (Ende exklusiv, wie bei range). json.dumps(objekt) macht aus einem Dict einen JSON-String. Mit sort_keys=True stehen die Schlüssel sortiert darin, und Zahlen als Schlüssel werden zu Strings: json.dumps({2: "b", 1: "a"}, sort_keys=True) ergibt '{"1": "a", "2": "b"}'. Welche Module genau geprüft werden, steht im offiziellen Syllabus des Python Institute (bitte vor der Prüfung gegen diese Liste prüfen).
Pakete von außen installierst du mit pip aus dem Register PyPI. Damit Projekte sich nicht gegenseitig stören, legt jedes eine eigene virtuelle Umgebung (virtual environment) an. Das Gegenstück zu node_modules:
| Aufgabe | Python | Node-Pendant |
|---|---|---|
| Paket installieren | pip install requests |
npm install axios |
| Installierte Pakete anzeigen | pip list, pip freeze |
npm ls |
| Abhängigkeiten festhalten | requirements.txt oder pyproject.toml |
package.json |
| Isolierte Umgebung | python -m venv .venv |
node_modules pro Projekt |
| Paket entfernen | pip uninstall requests |
npm uninstall axios |
| Registry | PyPI | npm Registry |
Venv und pip laufen im Browser nicht (kein Zugriff auf deine Maschine). Dafür gibt es die lokale Zusatzaufgabe am Ende.
Falle: die Prüfungs- und Praxisklassiker
- Zweiter Import führt das Modul nicht erneut aus. Nebenwirkungen auf Modulebene (print, Zähler) passieren einmal pro Programmlauf.
- Startcode ohne
if __name__ == "__main__":: läuft schon beim Import. Und Tippfehler wie"main"oder"__name__"im Vergleich lassen den Startcode nie laufen, ohne Fehlermeldung. - Stern-Import ohne
__all__bringt auch importierte Module und alle Namen ohne Unterstrich mit. Er kann Namen überschreiben. - Relativer Import in einer direkt gestarteten Datei: funktioniert nicht, er braucht ein Paket.
randintundrandrangeverwechseln:randint(1, 6)schließt die 6 ein,randrange(1, 6)nicht.
Übungen
Übung 1: Import-Cache und __name__ vorhersagen
Im Hintergrund liegt diese Datei zaehlmodul.py (du siehst sie nur hier):
start = []
start.append("geladen")
if __name__ == "__main__":
start.append("main")Dann läuft:
import zaehlmodul
import zaehlmodul as z2
from zaehlmodul import startTrage ein Tupel ein: (start, zaehlmodul.__name__, z2 is zaehlmodul).
Wie oft läuft der Code einer Datei, wenn mehrere import-Zeilen sie holen? Und was steht in __name__, wenn nicht du die Datei startest, sondern ein anderer Code sie lädt? Schritt 2 und 3.
antwort = (["geladen"], "zaehlmodul", True)
antwortÜbung 2: Stern-Import vorhersagen
Zwei Module liegen bereit:
# mit_all.py
__all__ = ["a", "b"]
a = 1
b = 2
c = 3
_p = 4
# ohne_all.py
import math
_p = 1
oeffentlich = 2
def f(): passWelche Namen bringt from mit_all import * und welche from ohne_all import * jeweils in den Namensraum? Trage ein Tupel aus zwei Mengen (set) ein.
Zuerst: Welche Regel gilt, wenn ein Modul __all__ hat, und welche, wenn nicht? Und zählt import math innerhalb eines Moduls zu dessen Namen? Schau auf die Beispielzelle am Ende von Schritt 4.
antwort = ({"a", "b"}, {"math", "oeffentlich", "f"})
antwortÜbung 3: Ein Paket anlegen
Schreibe die Funktion schreibe_paket(ordner). Sie soll im Ordner ordner ein Paket geometrie aus Dateien anlegen:
geometrie/kreis.pymit der Funktionflaeche(r), die die Kreisflächepi * r * rliefert (piausmath).- Ein klassisches Paket, sodass beide Zeilen funktionieren:
from geometrie import flaecheundfrom geometrie.kreis import flaeche.
Innerhalb des Pakets sollst du einen relativen Import nutzen.
Zwei Dateien müssen entstehen, und eine davon macht aus dem Ordner erst ein klassisches Paket und entscheidet, welche Namen direkt am Paket hängen. Ein relativer Import beginnt mit einem Punkt. Nutze write_text.
from pathlib import Path
def schreibe_paket(ordner):
paket = Path(ordner) / "geometrie"
paket.mkdir()
(paket / "__init__.py").write_text("from .kreis import flaeche\n")
(paket / "kreis.py").write_text(
"import math\n"
"\n"
"def flaeche(r):\n"
" return math.pi * r * r\n"
)
schreibe_paketÜbung 4: Den __name__-Guard reparieren
Dieser Modulquelltext (als String) führt haupt() schon beim Import aus. Repariere ihn: Beim Import darf LOG leer bleiben, beim direkten Start (python datei.py) muss haupt() genau einmal laufen. Gib den reparierten Quelltext zurück.
Der Aufruf unten steht ungeschützt auf Modulebene. Welche Bedingung unterscheidet “direkt gestartet” von “importiert”? Achte genau auf die Schreibweise der beiden Strings, ein Tippfehler lässt den Code unbemerkt nie laufen.
QUELLE = '''
LOG = []
def haupt():
LOG.append("haupt")
if __name__ == "__main__":
haupt()
'''
QUELLEÜbung 5: Standardbibliothek einsetzen
Schreibe wuerfel_bericht(seed, n). Ablauf: erst random.seed(seed), dann n mal ein Würfelwurf von 1 bis 6 (6 eingeschlossen), in dieser Reihenfolge. Rückgabe: ein JSON-String (json), der jede gewürfelte Augenzahl auf ihre Anzahl abbildet, mit sortierten Schlüsseln. Bei n = 0 ist das Ergebnis "{}". Gleicher Seed muss immer denselben String liefern.
Drei Bausteine aus dem Glossar: einer für reproduzierbare Zufallszahlen, einer fürs Zählen, einer fürs Ausgeben als Text. Bei der Wurffunktion entscheidet “Ende inklusive oder exklusiv” über die Augenzahl 6. Und json.dumps kennt ein Argument für sortierte Schlüssel.
import json
import random
from collections import Counter
def wuerfel_bericht(seed, n):
random.seed(seed)
zaehler = Counter(random.randint(1, 6) for _ in range(n))
return json.dumps(dict(zaehler), sort_keys=True)
wuerfel_berichtZusatz (lokal): venv und pip
Das läuft nicht im Browser, sondern auf deinem Rechner. Die Aufgabe liegt in lernlabor/uebung/python/python_05_venv_pip.py und enthält die Anleitung im Kopf der Datei. Kurz: Lege mit python3 -m venv .venv eine virtuelle Umgebung an, installiere dort requests mit pip und starte das Skript mit dem Python der Umgebung. Das Skript meldet, ob du wirklich in einer venv läufst und ob requests dort gefunden wird. Ein Teil dieser Übung ist ein Erkenntnisschritt: Vergleiche die Ausgabe mit und ohne venv.
Der Unterschied zwischen “Python der Umgebung” und “Python des Systems” liegt im Pfad des Interpreters, mit dem du das Skript startest.
# Terminal (macOS/Linux):
# cd lernlabor/uebung/python
# python3 -m venv .venv
# .venv/bin/pip install requests
# .venv/bin/python python_05_venv_pip.pyMerksatz und Prüfstein
Merksatz: Ein Modul läuft pro Programmlauf nur einmal (Cache in sys.modules), __name__ ist "__main__" nur beim direkten Start, und jeder Ordner mit einer __init__.py ist ein klassisches Paket.
Prüfstein (offene Frage): Erkläre in eigenen Worten, warum from m import * ohne __all__ auch ein Modul wie math in deinen Namensraum bringen kann, und warum das ein Argument gegen den Stern-Import ist.
Quelle: quellen/python-glossar-pcap-pcpp1.md, Abschnitt “Module, Pakete und Standardbibliothek” (Begriffe, Pakete installieren und isolieren, Standardbibliothek). Hinweis: runpy.run_path, sys.modules-Beispiele und Counter-Ausgabe stehen nicht alle in der Quelle, wurden aber mit Python 3.13 ausgeführt und geprüft (bitte prüfen, ob runpy in der PCAP geprüft wird). Prüfungsgewicht laut Quelle (Tabelle Prüfungsblöcke, Stand 1. Oktober 2026): Block 1 Module und Pakete, 6 Fragen, 12 %.