Module und Pakete¶
Module¶
Module bestehen, ebenso wie Python-Skript, aus Quellcode-Dateien mit der Endung
.py
. Prinzipiell kann somit jedes Python-Skript als eigenständiges
Python-Modul angesehen werden, es existieren allerdings auch Module, die nur nur
aus Hilfsfunktionen bestehen.
In der Praxis werden Module allerdings in erster Linie verwendet, um den Quellcode eines umfangreicheren Software-Projekts leichter zu organisieren und übersichtlich zu halten. Eine grobe Regel besagt, dass ein Modul nur so umfangreich sein sollte, dass sich seine Inhalte und sein Verwendungszweck mit ein bis zwei Sätzen zusammenfassen lassen sollten.
Jedes Modul stellt einen eigenen Namensraum für Variablen dar, so dass gleichnamige Funktionen, die in unterschiedlichen Modulen definiert sind, keine Konflikte verursachen.
Modulnamen werden in Python allgemein in Kleinbuchstaben geschrieben. Um in das
aktuelle Programm ein externes Modul, also eine andere .py
-Datei, zu
integrieren, ist folgende Syntax üblich:
import modulname
# Beispiel:
import antigravity
import this
Das zu importierende Modul muss sich hierbei im Python-Pfad befinden, also
entweder global installiert oder im aktuellen Verzeichnis enthalten sein.
Andernfalls ist eine Anpassung der Variablen sys.path
nötig.
Verwendung von Modulen
Nach dem Importieren eines Moduls können die im Modul definierten Klassen, Funktionen und Variablen mit folgender Syntax aufgerufen werden:
modulname.Klassenname
modulname.variablenname
modulname.funktionsname()
Um bei längeren Modulnamen Schreibarbeit sparen zu können, ist beim Importieren eines Moduls auch eine abkürzende Syntax möglich:
import modulname as myname
# Beispiel:
import math as m
Anschließend kann das Kürzel als Synonym für den Modulnamen verwendet werden,
beispielsweise m.pi
anstelle von math.pi
.
Eine weitere Vereinfachung ist möglich, wenn man nur einzelne Klassen oder Funktionen eines Moduls importieren möchte. Hierfür ist folgende Syntax möglich:
from modulname import Klassenname # oder
from modulname import funktionsname
Dabei können auch mehrere Klassen- oder Funktionsnamen jeweils durch ein Komma getrennt angegeben werden. Die so importieren Klassen bzw. Funktionen können dann direkt aufgerufen werden, als wären sie in der aktuellen Datei definiert.
Es ist auch möglich, mittels from modulname import *
alle Klassen und
Funktionen eines Moduls zu importieren. Hiervon ist allerdings (zumindest in
Skript-Dateien) dringend abzuraten, da es dadurch unter Umständen schwer
nachvollziehbar ist, aus welchem Modul eine später benutzte Funktion stammt.
Zudem können Namenskonflikte entstehen, wenn mehrere Module gleichnamige
Funktionen bereitstellen.
Hilfe zu Modulen
Mittels help(modulname)
kann wiederum eine Hilfeseite zu dem jeweiligen
Modul eingeblendet werden, in der üblicherweise eine Beschreibung des Moduls
angezeigt wird und eine Auflistung der im Modul definierten Funktionen. Bei den
Standard-Modulen wird zudem ein Link zur entsprechenden Seite der offiziellen
Python-Dokumentation https://docs.python.org/3/ angegeben.
Die __name__
-Variable
Jedes Modul bekommt, wenn es importiert wird, automatisch eine
__name__
-Variable zugewiesen, die den Namen des Moduls angibt. Wird
allerdings eine Python-Datei unmittelbar als Skript mit dem Interpreter
aufgerufen, so bekommt dieses „Modul“ als __name__
-Variable den Wert
__main__
zugewiesen.
Wenn Python-Module importiert werden, dann werden sie einmalig vom Interpreter ausgeführt, das heißt alle darin aufgelisteten Definitionen und Funktionsaufrufe werden zum Zeitpunkt des Importierens (einmalig) aufgerufen. Möchte man einige Funktionen in einer Python-Datei nur dann ausführen, wenn die Datei als Skript aufgerufen wird, nicht jedoch, wenn sie als Modul in ein anderes Programm eingebunden wird, so kann man dies mittels folgender Anweisung erreichen:
if __name__ == __main__:
# execute this only if the current file is interpreted directly
Dies ist insbesondere für Mini-Programme nützlich, die wahlweise als selbstständiges Programm aufgerufen, oder in ein anderes Programm eingebettet werden können.
Module erneut laden
Ist ein Modul einmal importiert, so wird jede weitere import
-Anweisung des
gleichen Moduls vom Python-Interpreter ignoriert. Dies ist in den meisten
Fällen von Vorteil, denn auch wenn beispielsweise mehrere Module eines
Programms das Modul sys
importieren, so wird dieses nur einmal geladen.
Schreibt man allerdings selbst aktiv an einem Programmteil und möchte die
Änderungen in einer laufenden Interpreter-Sitzung (z.B. Ipython) übernehmen,
so müsste der Interpreter nach jeder Änderung geschlossen und neu gestartet
werden. Abhilfe schafft in diesem Fall die im Modul imp
definierte Funktion
reload()
, die ein erneutes Laden eines Moduls ermöglicht:
import imp
import modulname
# Modul neu laden:
imp.reload(modulname)
Dies funktioniert auch, wenn ein Modul mit einer Abkürzung importiert wurde,
beispielsweise import modulname as m
; in diesem Fall kann das Modul mittels
imp.reload(m)
neu geladen werden.
Pakete¶
Mehrere zusammengehörende Module können in Python weiter in so genannten
Paketen zusammengefasst werden. Ein Paket besteht dabei aus einem einzelnen
Ordner, der mehrere Module (.py
-Dateien) enthält.
Ein Programm kann somit in mehrere Teilpakete untergliedert werden, die wiederum
mittels der import
-Anweisung wie Module geladen werden können. Enthält
beispielsweise ein Paket pac
die Module a
und b
, so können diese
mittels import pac
geladen und mittels pac.a
beziehungsweise pac.b
benutzt werden; zur Trennung des Paket- und des Modulnamens wird also wiederum
ein Punkt verwendet. Ebenso kann mittels import pac.a
nur das Modul a
aus dem Paket pac
geladen werden.
Die import
-Syntax für Pakete lautet somit allgemein:
# Alle Module eines Pakets importieren:
import paket
# Oder: Einzelne Module eines Pakets importieren:
import paket.modulname
# Alternativ:
from paket import modulname
Wird ein Modul mittels from paket import modulname
importiert, so kann es
ohne Angabe des Paketnamens benutzt werden; beispielsweise können darin
definierte Funktionen mittels modulname.funktionsname()
aufgerufen werden.
Eine weitere Verschachtelung von Paketen in Unterpakete ist ebenfalls möglich.
Relative und absolute Pfadangaben
Um Module aus der gleichen Verzeichnisebene zu importieren, wird in Python folgende Syntax verwendet:
# Modul aus dem gleichen Verzeichnis importieren
from . import modulname
Mit .
wird dabei der aktuelle Ordner bezeichnet. Ebenso kann ein Modul
mittels from .. import modulname
aus dem übergeordneten Verzeichnis und
mittels from ... import modulname
aus dem nochmals übergeordneten
Verzeichnis importiert werden. Dies ist allerdings nicht in der Hauptdatei
möglich, mit welcher der Python-Interpreter aufgerufen wurde und die intern
lediglich den Namen __main__
zugewiesen bekommt: Diese darf nur absolute
Pfadangaben für Imports enthalten.
Empfehlungen für Paket-Strukturen
Möchte man selbst ein Paket zu einer Python-Anwendung erstellen, so ist etwa folgender Aufbau empfehlenswert: [1]
My_Project/
|
|- docs
| |- conf.py
| |- index.rst
| |- installation.rst
| |- modules.rst
| |- quickstart.rst
| |- reference.rst
|
|- my_project/
| |- main.py
| |- ...
|
|- tests/
| |- test_main.py
| |- ...
|
|- CHANGES.rst
|- LICENSE
|- README.rst
|- requirements.txt
|- setup.py
|- TODO.rst
Das Projekt-Verzeichnis sollte den gleichen Namen wie die spätere Anwendung
haben, allerdings mit einem Großbuchstaben beginnen, um Verwechslungen mit dem
gleichnamigen Paket-Verzeichnis zu vermeiden. Das Projekt-Verzeichnis sollte
neben dem eigentlichen Projekt-Paket zumindest noch die Ordner docs
, und
test
umfassen, in denen eine Dokumentation des Projekts und zum Programm
passende Tests enthalten sind; zusätzlich kann das Projekt
einen lib
-Ordner mit möglichen C-Erweiterungen enthalten. In manchen
Projekten werden zudem ausführbare Programm-Dateien (meist ohne die Endung
.py
) in einem weiteren Ordner bin
abgelegt; hat ein Programm allerdings
nur eine einzelne aufrufbare Datei, so kann diese auch im
Projekt-Hauptverzeichnis abgelegt werden.
Die mit Großbuchstaben benannten Dateien sind selbsterklärend, die Dateien
requirements.txt
und setup.py
sind für die Installationsroutine
vorgesehen.
Paketinstallation mit setuptools
und setup.py
Das Paket setuptools
aus der Python-Standardbibliothek stellt einige
Funktionen bereit, die für das Installieren von Python-Paketen hilfreich sind.
Dazu wird üblicherweise im Projekt eine Datei setup.py
angelegt, die unter
anderem eine Programmbeschreibung, den Namen und die Emailadresse des Autors,
Informationen zur Programmversion und zu benötigten Fremdpaketen enthält.
Zudem können mit der Funktion find_packages()
aus dem setuptools
-Paket
die im Projektverzeichnis enthaltenen Pakete automatisch gefunden und bei Bedarf
installiert werden.
Python-Entwickler haben das setuptools
-Paket oftmals bereits installiert
(aptitude install python3-setuptools
), da es für das zusätzliche
Installieren von weiteren Paketen mittels pip3 install paketname
oder
easy_install3 paketname
hilfreich ist. Soll allerdings sichergestellt sein,
dass auch bei Anwendern das setuptools
-Paket installiert ist oder bei Bedarf
nachinstalliert wird, kann die Datei ez_install.py von der Projektseite heruntergeladen
und in das eigene Projektverzeichnis kopiert werden. In der Datei setup.py
sind dann üblicherweise folgende Routinen vorhanden:
try:
from setuptools import setup, find_packages
except ImportError:
import ez_setup
ez_setup.use_setuptools()
from setuptools import setup, find_packages
import os
import my_project
my_project_path = os.path.abspath(os.path.dirname(__file__))
long_description =
"""
Eine ausführliche Beschreibung des Programms.
"""
setup(
name='my_project',
version=my_project.__version__,
url='http://github.com/my_account/my_project/',
license='GPLv3',
author='Vorname Nachname',
author_email='name@adresse.de',
install_requires=[
'Flask>=0.10.1',
'SQLAlchemy==0.8.2',
],
tests_require=['nose'],
packages=find_packages(exclude=['tests']),
description='Eine kurze Beschreibung.',
long_description = long_description,
platforms='any',
keywords = "different tags here",
classifiers = [
'Programming Language :: Python',
'Development Status :: 4 - Beta',
'Natural Language :: English',
'Intended Audience :: Developers',
'Operating System :: Linux',
'Topic :: Software Development :: Libraries :: Application Frameworks',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
],
)
Anmerkungen:
[1] | Siehe auch Open Sourcing a Python Project the Right Way und Filesystem structure of a Python project für weitere Tips. |