Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Pakete, Module und Bibliotheken

Import external libraries and organize your code into functional chunks. For interactive reading and executing code blocks Binder and find b05-pypckg.ipynb, or install Python and JupyterLab locally.

Pakete oder Module importieren

Das Importieren eines Pakets oder Moduls in Python macht externe Funktionen und andere Elemente (wie Objekte) von Modulen in einem Skript zugänglich. Die Funktionen und andere Elemente werden in einer anderen Python-Datei (.py) im site-packages-Ordner (Regie) der Dolmetscherumgebung gespeichert. Um ein nicht standardmäßiges Paket zu verwenden, muss es zunächst heruntergeladen und installiert werden. Standard-Python-Pakete (z.B. os, math) sind immer zugänglich, und andere können mit conda oder pip (read more pip-installing) hinzugefügt werden.

Das os-Paket bietet grundlegende system-terminal-ähnliche Befehle zum Beispiel zur Verwaltung von Ordnerverzeichnissen. Also lasst uns dieses wesentliche Paket importieren:

import os
print(os.getcwd()) # print current working directory
print(os.path.abspath('')) # print directory of script running
/home/schwindt/github/hyhome-v2/jupyter
/home/schwindt/github/hyhome-v2/jupyter

Übersicht der Importoptionen

Hier eine Übersicht über die Optionen zum Import von Paketen oder Modulen (hierarchische Teile von Paketen):

| Befehl | Beschreibung | Verwendung von Attributen |

| import package-name | Importieren Sie ein Original-Modul | package.item() | | import package-name as nick-name | Import Modul und Umbenennen (alias) es im Skript |nick-name.item() | | from package-name import item | Importieren Sie nur eine Funktion, Klasse oder andere Elemente |item() | | from package-name import * | Alle Artikel eintragen | item() |

Beispiel

import matplotlib.pyplot as plt # import the pyplot module of the matplotlib package and alias it with plt

x = []
y = []

for e in range(1, 10):
    x.append(e)
    y.append(e**2)

plt.plot(x, y)

Was ist der beste Weg, um ein Paket oder Modul zu importieren?

Es gibt keine globale Antwort auf diese Frage. Beachten Sie jedoch, dass from package-name import * alle vorhandenen Variablen oder andere Elemente im Skript überschreibt. Verwenden Sie daher nur *, wenn Sie sich alle Inhalte eines Moduls oder Pakets bewusst sind. Aus diesem Grund entmutigt PEP 8Wildcard-Importe und empfiehlt, alle Importe an der Spitze eines Skripts zu platzieren. Die Einfuhrerklärung in der Mitte des folgenden Beispiels dient nur der Demonstration:

pi = 9.112 # define a float called pi
print(f"Pi is not {pi:.3f}.")

from math import pi # this overwrites the previously defined variable pi
print(f"Pi is {pi:.3f}.")

Welche Artikel (Beiträge, Klassen, Funktionen) sind in einem Modul?

Manchmal wollen wir Module erkunden oder variable Attribute überprüfen. Dies wird mit dem Befehl dir() erreicht:

import sys
print(sys.path)
print(dir(sys.path))

a_string = "zabaglione"
print(", ".join(dir(a_string)))
['/home/schwindt/miniforge3/envs/wrr-proj/lib/python311.zip', '/home/schwindt/miniforge3/envs/wrr-proj/lib/python3.11', '/home/schwindt/miniforge3/envs/wrr-proj/lib/python3.11/lib-dynload', '', '/home/schwindt/miniforge3/envs/wrr-proj/lib/python3.11/site-packages']
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
__add__, __class__, __contains__, __delattr__, __dir__, __doc__, __eq__, __format__, __ge__, __getattribute__, __getitem__, __getnewargs__, __getstate__, __gt__, __hash__, __init__, __init_subclass__, __iter__, __le__, __len__, __lt__, __mod__, __mul__, __ne__, __new__, __reduce__, __reduce_ex__, __repr__, __rmod__, __rmul__, __setattr__, __sizeof__, __str__, __subclasshook__, capitalize, casefold, center, count, encode, endswith, expandtabs, find, format, format_map, index, isalnum, isalpha, isascii, isdecimal, isdigit, isidentifier, islower, isnumeric, isprintable, isspace, istitle, isupper, join, ljust, lower, lstrip, maketrans, partition, removeprefix, removesuffix, replace, rfind, rindex, rjust, rpartition, rsplit, rstrip, split, splitlines, startswith, strip, swapcase, title, translate, upper, zfill

Neues Modul erstellen

Bei der objektorientierten Programmierung und Code Factorisierung ist das Schreiben von benutzerdefinierten, neuen Modulen eine wesentliche Aufgabe. Um ein neues Modul zu schreiben, erstellen Sie zunächst ein neues Skript. Dann öffnen Sie das neue Skript und fügen Sie einige Parameter und Funktionen hinzu.

# icecreamdialogue.py
flavors = ["vanilla", "chocolate", "bread"]
price_scoops = {1: "two euros", 2: "three euros", 3: "your health"}
welcome_msg = f"Hi, I only have {flavors[0]}. How many scoops do you want?"

icecreamdialogue.py can now either be executed as a script (nothing will happen visibly) or imported as a module to access its variables (e.g., icecreamdialogue.flavors):

import icecreamdialogue as icd
print(icd.welcome_msg)
scoops_wanted = 2
print(f"That makes {icd.price_scoops[scoops_wanted]} please")

Machen Sie Skript Stand-alone

As an alternative, we can append the call to items in icecreamdialogue.py in the script and run it as a stand-alone script by adding an if __name__ == "__main__": block:

# icecreamdialogue_standalone.py
flavors = ["vanilla", "chocolate", "bread"]
price_scoops = {1: "two euros", 2: "three euros", 3: "your health"}
welcome_msg = f"Hi, I only have {flavors[0]}. How many scoops do you want?"


if __name__ == "__main__":
    print(welcome_msg)
    scoops_wanted = 2
    print(f"That makes {price_scoops[scoops_wanted]} please")

Now we can run icecreamdialogue_standalone.py in a terminal (e.g., Linux Terminal, PyCharm’s Terminal tab at the bottom of the window, or VS Code’s integrated terminal).

C:\temp\ python icecreamdialogue_standalone.py

Standalone Scripts mit Eingabeparametern

Um das Skript flexibler zu gestalten, können wir beispielsweise scoops_wanted als Eingangsgröße einer Funktion definieren.

# icecreamdialogue_standalone_withinput.py
import sys # sys provides access to command line arguments

flavors = ["vanilla", "chocolate", "bread"]
price_scoops = {1: "two euros", 2: "three euros", 3: "your health"}
welcome_msg = f"Hi, I only have {flavors[0]}. How many scoops do you want?"

def dialogue(scoops_wanted): # formerly in the __main__ statement
    print(welcome_msg)
    print(f"That makes {price_scoops[scoops_wanted]} please")

if __name__ == "__main__":
    if len(sys.argv) > 1: # make sure input is provided
        # if true: call the dialogue function with the input argument
        dialogue(int(sys.argv[1]))

Jetzt können wir icecreamdialogue_standalone_withinput.py in einem Terminal ausführen.

C:\temp\ python icecreamdialogue_standalone_withinput.py 2

Initialisierung eines Pakets (Hierarchisch organisiertes Modul)

Gute Praxis beinhaltet, dass ein Skript 50-100 Zeilen Code nicht überschreitet (außer Inline-Docs und Multiline-Variablen). Folglich wird ein Paket höchstwahrscheinlich aus mehreren Skripten bestehen, die in einem Ordner gespeichert sind und ein Kernskript zur Initiierung der Skripte dient. Dieses Kernskript heißt __init__.py und Python ruft diesen Skriptnamen immer in einem Paketordner an. Beispielstruktur eines Pakets namens icecreamery:

  • icecreamery

    • __init__.py - Paketeinleitung Python Script

    • icecreamdialogue.py - Dialog mit der Produktion von Python Script

    • icecream_maker.py - virtuelles Eis erzeugen Python Script

Um die beiden relevanten Skripte (Submodule) des Pakets icecreamery automatisch einzugeben, muss die __init__.py Folgendes enthalten:

# __init__.py
print(f'Invoking __init__.py for {__name__}') # only for demonstration - keep __init__.py silent in production packages
import icecreamery.icecreamdialogue, icecreamery.icecream_maker
# example usage of the icecreamery package
import icecreamery
print(icecreamery.icecreamdialogue.welcome_msg)

Erinnern Sie sich an die dir() Funktion? Angewendet auf ein Paket (z.B. dir(icecreamery)) listet es die Elemente auf, die derzeit im Paketnamespace definiert sind. Um zu kontrollieren, welche Submodule einen Wildcard-Import (from icecreamery import *) laden, definieren Sie eine __all__-Liste in der __init__.py:

# __init__.py with __all__ list
__all__ = ['icecreamdialogue', 'icecream_maker']

Das komplette Beispiel des icecreamery_all Pakets ist auch in einem icecream Repository erhältlich.

# example usage of the icecreamery package
from icecreamery_all import *
print(icecreamdialogue.welcome_msg)

Zusammenfassung der Paketerstellung

Ein hierarchisch organisiertes Paket enthält eine __init__.py-Datei mit einer __all__-Liste, um relevante Modulskripte anzurufen. Die Struktur eines Moduls kann komplexer sein als die obige Beispielliste (z.B. mit Unterordner). Wenn Sie ein Paket schreiben, beachten Sie die Verwendung von meaningful script and variable names, zusammen mit einer entsprechenden Dokumentation.

Reload (Re-Import) eines Pakets oder Moduls

Seit Python 3 benötigt das Nachladen eines Moduls zunächst den Import des importlib Moduls. Das Nachladen ist nur sinnvoll, wenn Sie ein neues Modul aktiv schreiben. Um ein Modul neu zu laden, geben Sie:

import importlib
importlib.reload(my_module)

Paketentwicklung & PyPI (pip) Bereitstellung

Das icecreamery Beispiel zeigt, wie ein Paket intern funktioniert. Um ein Paket für jeden über pip install icecreamery zu installieren, muss es an PyPI, den Python Package Index, der pip im Hintergrund abfragt (recall pip-installing) bereitgestellt werden. Dieser Abschnitt fasst zunächst den Einsatz-Workflow zusammen, einschließlich der Automatisierung mit GitHub-Workflows und der Dokumentation zum Lesen der Docs und erklärt dann gute Praxis für die Entwicklung eines Pakets kollaborativ.

Von Local Code zu einem pip-installable Paket

Die moderne Python-Verpackung wird von einer einzigen pyproject.toml-Datei angetrieben, die die früher verwendete setup.py ersetzt (siehe PEP 621). Ein deployment-ready-Repository ähnelt der folgenden Struktur, die als src-Layout bekannt ist:

icecreamery/                  (repository root)
    src/
        icecreamery/          (the package itself)
            __init__.py
            icecreamdialogue.py
            icecream_maker.py
    tests/                    (automated tests, e.g., for pytest)
    docs/                     (documentation source, e.g., for Sphinx)
    examples/                 (functional usage examples)
    pyproject.toml            (package metadata and build configuration)
    README.md
    LICENSE

Die pyproject.toml-Datei definiert, wie pip (oder jeder andere Installer) das Paket baut und installiert:

[build-system]
requires = ["setuptools>=77"]
build-backend = "setuptools.build_meta"

[project]
name = "icecreamery"
version = "0.1.0"
description = "Virtual ice cream sales dialogues"
readme = "README.md"
license = "BSD-3-Clause"
requires-python = ">=3.10"
dependencies = [
    "matplotlib",
    "numpy",
]

Installieren Sie während der Entwicklung das Paket in editable mode in die aktive Umgebung:

pip install -e .

Mit der -e (eitable)-Flagge importiert Python das Paket direkt aus dem lokalen Entwicklungsklon anstelle einer statischen Kopie im Ordner site-Pakete, so dass Code-Änderungen sofort ohne Neuinstallation wirksam werden.

Um eine Veröffentlichung auf PyPI manuell zu implementieren:

  1. Registrieren Sie sich (kostenlos) unter pypi.org und für die Probenaufnahme unter test.pypi.org.

  2. Erstellen Sie das Distributionsarchiv (ein Quellarchiv und ein Rad) mit python -m build (installieren Sie den Builder einmal mit pip install build). Die Archive landen in einem neuen dist/-Ordner.

  3. Hochladen der Archive mit twine: python -m twine upload dist/*. Best Practice: proben Sie zuerst den Upload mit python -m twine upload --repository testpypi dist/*.

Fertig. Ab sofort kann jeder pip install icecreamery.

Automatische Prüfung und Bereitstellung mit GitHub Workflows

Die manuelle Erstellung und das Hochladen jeder Veröffentlichung ist fehleranfällig. GitHub Actions automatisieren solche wiederkehrenden Jobs mit sogenannten Workflows, die YAML-Dateien sind, die im .github/workflows/Ordner eines Repository gespeichert sind. Für die Paketentwicklung sind zwei Workflows besonders nützlich:

  • Ein -Test (kontinuierliche Integration) Workflow, der die Testsuite (z.B. mit pytest) für jede Push- und Pull-Anforderung betreibt, ideal auf mehreren Python-Versionen und Betriebssystemen. So wird der defekte Code markiert, bevor er in main zusammengeführt wird (Recall theCollaboration & Branchessection).

  • Ein publish Workflow, der das Paket auf PyPI baut und hochlädt, wenn auf GitHub ein neues Release (Versions-Tag) veröffentlicht wird.

Best Practice für den Publikations-Workflow ist PyPIs Trusted Publishing, die das GitHub-Repository direkt an das PyPI-Projekt (ein einmaliges Setup in den PyPI-Kontoeinstellungen) verlinkt, so dass keine API-Token in den Repository-Geheimnen gespeichert werden müssen:

# .github/workflows/publish.yml
name: Publish to PyPI

on:
  release:
    types: [published]

jobs:
  publish:
    runs-on: ubuntu-latest
    environment: pypi
    permissions:
      id-token: write   # required for PyPI Trusted Publishing
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - name: Build distribution archives
        run: |
          python -m pip install build
          python -m build
      - name: Upload to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1

Mit diesem Workflow reduziert sich die Veröffentlichung einer neuen Version auf die Erhöhung der Versionsnummer in pyproject.toml und klicken auf *Draft eine neue Veröffentlichung (mit einem Tag wie v0.1.1) auf GitHub.

Dokumentation zum Lesen der Docs (Freier Plan)

Ein pip-installierbares Paket ohne Dokumentation wird von niemandem kaum genutzt. Der de-facto-Standard für die Hosting-Python-Paketdokumentation ist Lesen Sie die Docs, die die Dokumentation der öffentlichen (offene) Repositories kostenlos unter PACKAGE-NAME.readthedocs.io erstellt und beherbergt (der kostenlose Plan zeigt kleine Anzeigen). Der Workflow:

  1. Schreiben Sie konsistente Docstrings (z.B. in numpy oder Google style) für alle Module, Klassen und Funktionen, so dass Dokumentationsgeneratoren die API-Referenz automatisch vornehmen können.

  2. Erstellen Sie einen docs/-Ordner mit einem Sphinx-Projekt (sphinx-quickstart) und aktivieren Sie die sphinx.ext.autodoc- und sphinx.ext.napoleon-Erweiterungen unterdocs/conf.py, um die Docstrings in die Dokumentation zu ziehen. MkDocs mit dem mkdocstrings Plugin ist eine beliebte Alternative.

  3. Fügen Sie eine .readthedocs.yaml-Konfigurationsdatei (erforderlich von Read the Docs) zum Repository-Root hinzu:

# .readthedocs.yaml
version: 2

build:
  os: ubuntu-24.04
  tools:
    python: "3.12"

sphinx:
  configuration: docs/conf.py

python:
  install:
    - method: pip
      path: .
    - requirements: docs/requirements.txt
  1. Melden Sie sich unter readthedocs.org mit einem GitHub-Konto an und importieren Sie das Repository. Lesen Sie die Docs installiert einen Webhook, so dass jeder Push an main einen automatischen Neuaufbau der Dokumentation auslöst und jeder Release-Tag als versionsspezifische Dokumentation erstellt werden kann.

Fertig. Die Dokumentation aktualisiert sich nun mit jedem Push.

Kooperationspaketentwicklung

Sobald mehrere Entwickler (z.B. eine Forschungsgruppe) den Code an das gleiche Paket-Repository drücken, ist die Arbeit an dedicated branches with pull requests nur die Hälfte der Geschichte. Die folgenden guten Praxisregeln halten ein wachsendes Paket aufrecht erhalten (diese Liste beruht auf schmerzhaften Erfahrungen mit real-world-Forschungscode):

** Beachten Sie bitte PEP 8:**

  • Naming Conventions: stellen Sie sicher, dass alle Skript- (Modul)-Dateinamen und variable Namen gute Praxis, d.h. kurz, lowercase_with_underscoresNamen für Module, Funktionen und Variablen, CamelCase für Klassen und UPPERCASE für Konstanten (Recall meaningful script and variable names) folgen.

  • Modulschattierung: Nennen Sie niemals ein internes Skript oder einen Ordner nach einer installierten Bibliothek oder einem Modul (z.B. math.py, numpy.py oder einen Ordner namens matplotlib/). Da Python das eigene Verzeichnis des Skripts vor dem Ordner site-packages durchsucht, wird die lokale Datei anstelle der vorgesehenen Bibliothek importiert, was zu scheinbar unerklärlichen Importausfällen führt. Übermäßig generische Namen, wie z.B. plots.py oder plots/, sind aus demselben Grund riskant: Sie kollidieren leicht mit Drittanbieter-Modulen und verwechseln sich mit Plot-Bibliotheken wie matplotlib.pyplot.

  • Docstrings: Bestücken Sie jedes Modul und jede Funktion mit einem Docstring, so dass Mitarbeiter (und Dokumentations-Generatoren, siehe oben) verstehen, was der Code tut, ohne ihn umzudrehen.

  • File Länge und Code Redundanz: Eine modulare Paketstruktur bedeutet, dass Skripte präzisiert bleiben sollten. Für den Kontext mussten wir einmal ein Ploting-Skript refaktorieren, das auf mehr als 3500 Zeilen gewachsen war, zum Teil aufgrund von kopierten (redundant) Codeblöcken. Brechen Sie große Dateien in logische Sub-Module und folgen Sie streng dem DRY-Prinzip (Nicht wiederholen Sie sich selbst).

** Verwenden Sie dedizierte Ordner für Beispiele und Vorlagen*, um das Kernpaket (d.h. das src/-Verzeichnis) sauber zu halten:

  • dev-examples/: laufende Forschungs- oder Entwicklungsfälle (z.B. dev-examples/cylinder-flume-telemac/). Konfigurieren Sie das Repository, um große Dateien (z.B. über 20 MB) zu blockieren, da große Simulationsausgänge nicht in einem git-Repository gehören und separat gesichert werden sollten.

  • examples/: fertiggestellte, gereinigte und funktionale Beispiele, zusammen mit README Informationen über die Ausführung.

  • templates/: Verallgemeinerte Versionen der Beispiel-Skripte, die Keyword-Argumente anstelle von hardcoded Pfaden verwenden.

*Heilige Top-Level-Reinigung: Dateien nicht direkt in die Repository-Root oder das Paket-Source-Verzeichnis hinzufügen oder verschieben. So halten Sie z.B. Umgebungsaktivierungsskripte in einem dedizierten Ordner (z.B. env-scripts/) und rufen Sie diese nach Bedarf aus Ihrer lokalen Umgebung oder Beispielverzeichnissen an.

Stay synchronisiert mit main: Ziehen Sie die neueste main Filiale regelmäßig und immer vor der Schaffung einer neuen Filiale. Darüber hinaus installieren Sie das Paket aus dem lokalen Entwicklungs-Klon im bearbeitbaren Modus (pip install -e .) statt relative Importe oder sys.path zu manipulieren, so dass Beispielskripte Ihren neuesten lokalen Code importieren anstatt eine global installierte site-Pakete Kopie. KI-Assistenten (z.B. Claude Code oder Codex) können dazu beitragen, alte Skripte mit gebrochenen Importen robust umzugestalten, aber ihre Modifikationen so kritisch wie jede andere Zuganforderung zu überprüfen.

Erfolgsprüfung lernen

Nehmen Sie den Lernerfolgstest für dieses Jupyter Notebook.