Module sind in Python ein weiteres Mittel, den Quellcode übersichtlich zu organisieren. Während Klassen eher auf Ebene des Quellcodes optimieren, machen Module das eher im Dateisystem.
Durch Klassen musst du nicht mehr alle Variablen und Methoden in eine Datei klatschen, dank Modulen liegt nicht mehr jede Datei in ein und demselben Verzeichnis.
Module
Module werden mittels import
in eingebunden, dass hast du im dritte Teil bereits mit dem Modul math
gesehen. Ein Modul fasst Klassen zu einer logischen Einheit zusammen, die anderswo wieder verwendet werden können. Spätestens bei der Benutzung von Sensoren am GPIO des Raspberry Pi brauchst du Module, um nicht die Schnittstelle zum Sensor selbst programmieren zu müssen.
Du erinnerst dich sicher an die Dateien person.py
und anschrift.py
aus dem letzten Teil. Person importierte Anschrift mit dieser Zeile
from anschrift import Anschrift
Das macht Anschrift schon zum Modul, denn alles, was du in anschrift.py hineinschreibst, kannst du in anderen Dateien importieren. Allerdings stoßen wir dabei wieder auf das Problem, dass eine Quellcode-Datei zu umfangreich und schlecht lesbar wird.
Pakete
Dieses Problem lösen Pakete (engl.: packages), in denen du zusammengehörige Dateien sinnvoll organisieren kannst. Während bei Java jedes Package explizit in den „Classpath aufgenommen werden muss, reicht in Python ein einfaches Unterverzeichnis.
mkdir partner
In diesem Verzeichnis wollen wir alle Dateien für ein kleines Partnersystem organisieren. Dazu erstellst du im partner
Verzeichnis die folgenden drei Dateien:
Person.py
from partner.Anschrift import Anschrift
class Person:
# Konstruktor
def __init__(self,vorname, name,anschrift):
self.vorname = vorname
self.name = name
if anschrift == None:
raise TypeError('anschrift darf nicht None sein')
if not isinstance(anschrift, Anschrift):
raise TypeError('anschrift ist vom falschen Typ')
self.anschrift = anschrift
In dieser Version wird die Anschrift
komplett als Objekt an den Konstruktor übergeben. Da er ein Pflichtparameter ist, wird überprüft, ob er None
ist und in dem Fall dann ein TypeError
geworfen. Das Thema Exceptions
behandle ich später noch. Ebenso muss anschrift
natürlich auch vom Typ Anschrift
sein.
Telefonnummer.py
class Telefonnummer:
def __init__(self, lkz, vorwahl, nummer):
self.lkz = lkz
self. vorwahl = vorwahl
self.nummer = nummer
def __str__(self):
return f'+{self.lkz}-{self.vorwahl}/{self.nummer}'
Anschrift.py
class Anschrift:
def __init__(self, strasse, hausnummer, plz, ort):
self.strasse = strasse
self.hausnummer = hausnummer
self.plz = plz
self.ort = ort
def __str__(self):
return f'{self.strasse} {self.hausnummer} \n {self.plz} {self.ort}'
Damit hast du alle Klassen erstmal definiert. Damit Python weiß, dass das Verzeichnis partner
ein Paket ist, braucht es noch eine spezielle Datei namens __init__.py
im Verzeichnis partner
from . import Telefonnummer
from . import Person
from . import Anschrift
__all__ = ['telefonnnummer','person','anschrift']
Du erkennst an den doppelten Unterstrichen, dass diese Datei für die interne Verwendung in Python vorgesehen ist.
Ist diese Datei in einem Verzeichnis vorhanden, behandelt Python es als Package.
Wir teilen dem Python-Interpreter in der __init__.py
mit, welche Dateien zum Package gehören ( die drei from . import
Zeilen) und was er machen soll, wenn er alle Klassen des Pakets importieren soll (__all__
Zeile).
Packages und Module werden dir ständig über den Weg laufen, gerade dann, wenn wir Sensoren und Aktoren an die GPIO Leiste des Raspberry Pi anschließen, nehmen uns die Module der Hersteller viel Arbeit ab.
Im nächsten Kapitel zeig ich dir ein bisschen mehr zu Exceptions.