Module

Was sind Module?

Python organisiert Sourcecode in Modulen. Ein Modul ist nichts anderes, als eine Datei mit der Extension .py.

Module dienen dazu,

  • große Projekte in mehrere kleinere überschaubare (und logisch zusammenhängende) Sourcecode-Dateien zu organisieren
  • Code besser wiederverwendbar zu machen, da Module selektiv in neuen Code importiert werden können

Kleine Skripte kann man ohne weiteres in eine einzige Datei packen. Sobald ein Programm aber mehr als ein paar hundert Zeilen hat, empfiehlt es sich, den Code auf mehrere Module aufzuteilen, auch weil der Code dadurch einfacher zu pflegen und zu testen ist.

Module sind überall

Nicht nur der eigene Programmcode lässt sich in Modulen organisieren, auch fremder Code wird in Modulen verteilt:

  • Die Standard-Library von Python ist in Modulen (und Paketen) organisiert
  • Third-Party-Libraries sind ebenfalls als Module verfügbar

Module müssen importiert werden

Damit ein Modul im eigenen Programm verwendet werden kann, muss das Modul zuerst importiert werden:

import <Modulname>

Danach steht das Modul mit der dort definierten Funktionalität zur Verfügung. Das in der mit Python mitinstallierten Standardlibrary vorhandene Modul random stellt eine Reihe von Zufalls-Funktionen bereit. Damit wird diese verwenden können, müssen wir das Modul zuerst importieren:


In [ ]:
import random

Danach können wir uns beispielsweise eine Zufallszahl generieren lassen:


In [ ]:
random.randint(0, 1000000)

Module und Namensräume

Im letzten Beispiel haben wir nicht irgendeine Funktion mit dem Namen randint verwendet, sondern genau die, die vom Modul random bereit gestellt wird.

Module strukturieren daher nicht nur den Sourcecode, sondern bilden auch Namensräume, wodurch verhindert wird, dass sich beispielsweise zwei in unterschiedlichen Modulen definierte, gleichnamige Funktionen gegenseitig überlagern. Um das zu verdeutlichen habe ich im Verzeichnis, in dem dieses Notebook liegt, zwei minimale Module angelegt:

  • a.py
  • b.py

In beiden Modulen gibt es eine Funktion serialize(), die wir unter Nutzung der Namensräume beide in unserem Programm nutzen können:


In [ ]:
import a
import b

a.serialize()
b.serialize()

Der Namensraum ist einfach der Name der Datei, die das Modul repräsentiert.

Im obigen Beispiel gibt es also ein Modul (d.h. eine Datei) a.py und ein zweites Modul b.py.

Module importieren

Wir haben bereits gehört, dass wir Module importieren müssen, ehe wir sie verwenden können. Dazu gibt es verschiedene Möglichkeiten. Die einfachste haben wir bereits kennengelernt: Wir importieren das gesamte Modul unter Beibehaltung des Modulnamens. Als Beispiel verwenden wir wieder ein Modul aus der Standard-Library: sys stellt Informationen zur aktuellen Systemumgebung bereit:


In [ ]:
import sys
sys.version

In [ ]:
sys.platform

Nur einen Teil eines Moduls importieren

Manchmal sind wir nur an einem kleinen Teil eines Moduls interessiert, zum Beispiel wenn wir nur die aktuelle verwendetet Plattform herausfinden wollen:


In [ ]:
from sys import platform
platform

Achtung: Hier haben wir etwas aus einem Modul in den globalen (bzw. unseren eigenen) Namensraum importiert. Wir ersparen uns dadurch zwar Tipparbeit, handeln uns aber auch einige Probleme ein, weil wir den eigenen Namensraum verschmutzt haben:

  • Wir haben die Nachvollziehbarkeit unseres Codes erschwert, weil beim Lesen des Codes erst herausgefunden werden muss, was es mit diesem platform auf sich hat - sys.platform ist hier viel klarer.
  • Wir können uns Seiteneffekte einhandeln, wenn wir uns u.U. unbeabsichtigt eigene Variablen überlagern.

Hier ein Beispiel:


In [ ]:
version = '0.9 beta'
print('Sie verwenden MeinProgramm in Version {}'.format(version))

# Imports sollten immer ganz oben passieren, man kann sie aber überall verwenden
from sys import version 
print('Sie verwenden MeinProgramm in Version {}'.format(version))

Noch schlimmer ist diese Version:


In [ ]:
version = '0.9 beta'

# Imports sollten immer ganz oben passieren, man kann sie aber überall verwenden
from sys import *
print('Sie verwenden MeinProgramm in Version {}'.format(version))

Hier haben wir alles aus dem Modul sys in unseren eigenen Namespace importiert. Wir waren uns möglicherweise gar nicht bewusst, dass es in sys eine Variable version gibt, die unsere eigene Variable überlagert. Schwer zu findende Fehler sind so vorprogrammiert!

Kleiner Exkurs: wenn Sie feststellen wollen, was in einem Modul vorhanden (und was wir beim letzten Beispiel allen in unseren Namensraum importiert haben) ist, können Sie die dir() Funktion verwenden:


In [ ]:
import sys
dir(sys)

Namensräume umdefinieren

Manche Namensräume sind sehr lange und es ist daher mühsam, diese immer einzutippen. Deshalb besteht die Möglichkeit, einem Modul einen eigenen Namen zuzuweisen. pyplot ist ein Modul des mächtigen matplotlib Pakets. (Achtung: Dieses Paket ist nicht in der Standard-Library und muss möglicherweise erst nachinstalliert werden).

Hier zuerst die umständliche Variante:


In [ ]:
import matplotlib.pyplot
matplotlib.pyplot.plot([1, 2, 3, 4, 4, 3, 5, 6, 6, 3, 3, 4])
matplotlib.pyplot.show()

Normalerweise schreibt man das allerdings so, um sich Tipparbeit zu sparen:


In [ ]:
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4, 4, 3, 5, 6, 6, 3, 3, 4])
plt.show()

Module und Docstrings

So wie eine Funktion durch einen Docstring beschrieben werden kann, funktioniert das auch für Module. Dazu muss man einfach direkt am Anfang der Modul-Datei den entsprechenden Docstring schreiben. Im Verzeichnis dieses Notebooks finden sie eine Datei (d.h. ein Modul) mystring.py. Da dieses Modul über einen DocString verfügt, können diesen auslesen:


In [ ]:
import mystring
help(mystring)

In [ ]:
mystring.reverse('abc')

In [ ]:
mystring.distinct_len('Mississippi')

Wie werden Module gefunden?

Module können an unterschiedlichen Stellen im Filesystem liegen. Hier wird kurz beschrieben, wo und wie Python nach Modulen sucht. Dabei kommt eine bestimmte Reihenfolge zum Einsatz. Sobald das (oder zumindest ein gleichnamiges) Modul gefunden wird, wird dieses verwendet. Diese Reihenfolge ist:

  1. Das aktuelle Verzeichnis.
  2. Alle Verzeichnisse, die in der Umgebungsvariable PYTHONPATH definiert sind.
  3. Abhängig von der aufgerufenen Python-Version in bestimmten Verzeichnissen, in denen beispielweise die Standard Library liegt.

Das sys-Modul weiß, wo gesucht wird:


In [ ]:
sys.path

sys.path ist übrigens eine normale Liste, die z.B. erweitert werden kann (was aber, wenn Sie Ihr Programm weitergeben wollen, keine besonders gute Idee ist).

Module und Bytecode

Wenn ein Modul zum ersten Mal von Python geladen wird, übersetzt es den Code in Bytecode und speichert diesen in eine eigene Datei, damit das Modul bei zukünftigen Aufrufen schneller geladen werden kann. Diese Bytecode-Dateien haben die Dateinamenerweiterung .pyc und liegen unter Python3 im Verzeichnis __pycache__. Sowohl dieses Verzeichnis als auch einzelne pyc-Datei können gefahrlos gelöscht werden, weil Sie bei Bedarf automatisch neu erzeugt werden.

Pakete

Wenn man größere Projekte tiefer organisieren will, kann man mehrere Module (und sogar Subpakete) zu einem Paket zusammenfassen.

Ein Paket ist nichts anderes, als ein Verzeichnis, das Module enthält. Zu einem Paket wird ein solches Verzeichnis allerdings erst, wenn im Verzeichnis eine Datei __init__.py existiert. Diese Datei kann leer sein.

Ein Modul in einem Paket wird durch den Punkt-Operator getrennt angesprochen:

>>> import os
>>> if os.path.exists('daten.csv'):
...

Virtualenv und Environments

Wenn man parallel an mehreren Projekten arbeitet oder fremde Python-Programme verwendet, kann es passieren, dass diese unterschiedle Bibliotheken benötigen, vielleicht sogar unterschiedliche Versionen derselben Bibliothek. Es ist daher sehr empfehlenswert, unterschiedliche, voneinander isolierte Python-Umgebungen zu verwenden. Diese sind allgemein für Python virtualenv und für Conda bzw. Anaconda environments.

Virtualenv

Diese virtuellen Umgebungen isolieren Python weitgehend vom systemweit installierten Python. Ein Virtualenv verwendet zwar einen der systemweit installierten Python-Interpreter, alle zusätzlich installierten Pakete und Module sind jedoch spezifisch für diese eine Umgebung.

Dadurch ist es möglich, bestimmte Module nur für ein bestimmtes Projekt zu installieren oder ein Modul in unterschiedlichen Versionen für verschiedene Projekte zu verwenden.

Nicht zuletzt sind Virualenvs praktisch, um erste Experimente mit einem Zusatzmodul anzustellen ohne deshalb gleich das Modul systemweit installieren zu müssen.

Um die Verwaltung von virtuellen Python-Umgebungen kümmert sich ein Programm mit dem Namen virtualenv. Dieses muss zusätzlich zu Python installiert werden. (IDEs wie PyCharm bringen virtualenv automatisch mit).

http://virtualenv.pypa.io/

Mit virtuellen Umgebungen arbeiten

Wichtiger Hinweise: virtualenv ist ein Kommandozeilenprogramm. Die hier beschriebenen Befehle können daher nicht in einem Notebook ausgeführt werden!

Zunächst muss man ein Virtualenv anlegen:

virtualenv zielverzeichnis
bzw.
virtualenv -p c:\python3.5\bin\python zielverzeichnis

Die erste Zeile legt im Verzeichnis zielverzeichnis eine neue virtuelle Python-Umgebung an. Falls man eine bestimmte Version von Python verwenden will, kann man diese explizit mit der Option -p angeben (letzte Zeile).

Danach (und zu Beginn jeder Arbeits-Sitzung) muss dieses Virtualenv aktiviert werden:

<venv-verzeichnis>\Scripts\activate  # Windows
source <venv-verzeichnis>/bin/activate  # OS X, Linux

Mit deactivate kann man das Virualenv wieder deaktivieren.

Virtualenv in Pycharm

IDEs wie Pycharm bietet direkt aus der IDE heraus die Möglichkeit, Virtualenvs anzulegen und zu aktivieren.

In einem virtuellen Environment arbeiten

Sobald eine virtuellen Umgebung aktiviert ist, können Pakete in gewohnter Weise installiert werden:

pip install paketname

Diese werden dann nur in dem aktiven Virtualenv installiert.

Eine virtuelle Umgebung sichern

Mit pip lassen sich virtuelle Umgebungen relativ leicht dokumentieren:

pip freeze > requirements.txt

Die Datei requirements.txt enthält nun Informationen über alle installierten Zusatzmodule incl. Versionsinformation.

Um genau diese Zusatzmodule in einem neuen Virtualenv wieder zu installieren, reicht dieser Befehl:

pip install -r requirements.txt

Conda Environments

Conda Environments funktioren von der Idee her sehr ähnlich wie virtuelle Environments.

Ein Environment anlegen

Ein neues Environment wird so angelegt:

conda create --name myenv

Bei Bedarf kann auch hier eine bestimmte Python-Version angegeben werden:

conda create -n myenv python=3.2

Ein Environment aktivieren

Um ein Environment zu aktivieren muss unter Windows dieser Befehl eingegeben werden:

activate myenv

Unter OS X und Linux geht das Aktivieren so:

source activate myenv

Eine ausführliche Beschreibung zur Arbeit mit Environments findet sich hier: https://conda.io/docs/user-guide/tasks/manage-environments.html


In [ ]: