.. include:: markup.rst *************** Modularisierung *************** Darunter versteht man die Aufteilung des Quelltextes in einzelne Teile, sogenannte :mark:`Module`. Es gibt 2 Möglichkeiten: * Das Einbinden von :mark:`Bibliotheken` (engl. Libraries) oder * die Modularisierung :mark:`eigener Programmteile` (Funktionen, Klassen) durch Aufteilung in eigene Dateien um sehr langen Programmcode überschaubar zu machen. Diese Dateien können wie Bibliotheken eingebunden werden Es ist möglich sowohl eigene Bibliotheken, die Python Standardbibliothek oder Bibliotheken eines Drittanbieters einzubinden. Einbinden externer Programmbibliotheken ======================================= Je nach verwendeter Python Version, müssen eventuell vorab :mark:`Bibliotheken installiert` werden. Danach können diese mit einer ``import`` :mark:`Anweisung` eingefügt und verwendet werden: :: In [1]: import math In [2]: print(math.sin(math.pi)) 1.2246467991473532e-16 Der Zusatz ``math`` vor ``sin`` zeigt an, welche ``sin()`` Funktion verwendet werden soll (jene aus dem Modul bzw. Namensraum ``math``). Mit ``globals()`` nach dem ``import`` sieht man was passiert! :: In [3]: globals() Out[3]: {'__name__': '__main__', ... '_i1': 'import math', 'math': , '_i2': 'print(math.sin(math.pi))', '_i3': 'globals()'} Bei langen bzw. oft verwendeten Namen schreibt man: :: import numpy as np np.array([1,2,3]) .. hint:: Verwenden Sie nicht die Anweisung: :: from math import * um Überraschungen zu vermeiden. Es werden dadurch alle Funktionen in den Namensraum geladen. Anbei ein Beispiel: :: In [1]: pi = 1234 # meine definierte Variable pi In [2]: pi Out[2]: 1234 In [3]: from math import * # importiere Modul, darin gibt es auch pi! In [4]: pi # mein altes pi wurde ueberschrieben Out[4]: 3.141592653589793 Beachte dass die Variable ``pi`` durch den Import überschrieben wurde ohne aufzufallen. Einige interessante Python Module: ---------------------------------- Eine Liste der Pakete, die für Ihre Anaconda-Installation verfügbar sind finden Sie unter folgendem Link: Packages_ Einige interessante Pakete sind (Details später) z.B.: * math_: Mathemtische Funktionen wie cos, sin, exp, etc. und mathematische Konstanten wie pi, e, etc. * numpy_: Package zum einfachen Arbeiten mit Vektoren und Matrizen, linearer Algebra, etc. * matplotlib_: Plotten und Illustrieren von 2- und 3-dimensionalen Daten. * scipy_: Mathematische Operationen wie Integrieren von Funktionen, Interpolieren von Datenpunkten, Optimierung, etc. * openpyxl_: Schreiben und Lesen von Excel-Files mittels python. .. _Packages: https://docs.anaconda.com/anaconda/packages/pkg-docs .. _math: https://docs.python.org/2/library/math.html .. _numpy: http://www.numpy.org/ .. _matplotlib: https://matplotlib.org/gallery/index.html .. _scipy: https://docs.scipy.org/doc/scipy/reference/ .. _openpyxl: https://openpyxl.readthedocs.io/en/stable/ Eigene Module ============= Die Verwendung eines eigenen Moduls ist sehr einfach und besteht aus 2 Schritten: 1) Erstellung des Moduls = :mark:`Python Skript` z.B. ``modul_name.py`` mit Funktionen, Klassen, etc. 2) Einbinden des obigen Files in ein :mark:`Hauptprogrammes` z.B. ``programm.py`` mit: :: import meinModul Im folgenden ein Beispiel eines :mark:`Mathematik Moduls`. Zunächst wird ein :mark:`Modulfile` ``dpMath.py`` mit folgenden Inhalt erzeugt: .. literalinclude:: src/dpMath.py .. hint:: Ein Tipp zur Namensgebung des Files mit dem Modul: * Initialen des Erstellers, Projektes, etc hier ``dp`` gefolgt von * markantem Namen der den Inhalt beschreibt (``Math``). Als zweiter Schritt wird das :mark:`Hauptprogramm` erstellt z.B. ``modul_demo.py``, indem das Modul geladen wird: .. literalinclude:: src/modul_demo.py Aber: Woher weiss Python, :mark:`wo` ``dpMath.py`` :mark:`ist`? Dazu sollte man wissen: * Python sucht zunächst in dem Verzeichnis in welchem ``modul_demo.py`` gestartet wurde. * Findet es dort ``dpMath.py`` nicht, sucht es an Stellen des :mark:`Systempfades` "``PYTHONPATH``". Eventuell muss dieser von Hand gesetzt werden (siehe dazu WWW). Abschließend noch ein Beispiel wie man beides (Modul und Modultest) kombinieren kann. Dazu erzeugt man ein Pythonskript mit 2 Teilen: :: # Teil 1: Wird bei 'import' Anweisung importiert, # beim Skriptaufruf NICHT ausgefuehrt. def meineFunktion(): # Es folgt die Implementierung ... print("Funktion meineFunktion() wurde aufgerufen!") # Teil 2: Wird bei 'import' Anweisung NICHT importiert, # beim Skript Aufruf ausgeuehrt. if __name__ == '__main__' : # Hier stehen z.B. Funktionstests. meineFunktion() Pakete ====== :mark:`Mehrere Module` kann man in einem sogenannten :mark:`Paket` zusammenfassen bzw. kapseln. Zum Beispiel ``effekte.blur`` verweist auf ein Untermodul ``blur`` im Paket ``effekte`` (siehe Abbildung `Beispiel einer Paketstruktur`_). .. _`Beispiel einer Paketstruktur`: .. figure:: images/packet.png :scale: 100 % :align: center Beispiel einer Paketstruktur So wie Module davor bewahren sich Sorgen um andere (gleichlautende) globale Variablennamen zu machen (siehe Beispiel mit ``pi`` oben), bewahren Pakete davor sich Sorgen um andere Modulnahmen zu machen. Übungsbeispiele ==================== **Aufgabe 6.1** Verändern Sie Ihre Lösung zu Aufgabe 5.1, sodass die Funktion ``berechne_Distanz`` nicht im selben Skript definiert wird, sondern importiert wird. Welche verschiedene Arten gibt es das zu tun? weitere Übungsbeispiele ================= **Aufgabe 6.2** Ausgangspunkt ist das Pythonskript aus Aufgabe 5.3 mit der Funktion ``Negiere(A)``, welches mit Vektoren und Matrizen operiert. 1) Importieren Sie das File als Modul in ein leeres Python Skript. 2) Testen Sie die Funktion mit entsprechen Vektoren und Matrizen mittels ``print`` Ausgaben. 3) Importieren Sie das Paket ``numpy`` mittels ``import numpy``. 4) Definieren Sie ensprechende Vektoren und Matrizen mit ``numpy.array(..)``. Verwenden Sie die gleichen Werte wie unter Punkt 2. 5) Testen Sie das Negieren (einfach mittels ``-``) und vergleichen Sie das Ergebnis mit dem durch die Funkition ``Negiere(..)``.