Module

Grundlegendes

Datei als Eingabe für den Python Interpreter

Wenn der Python-Interpreter (in einem Terminal-Fenster) geschlossen und anschliessend wieder geöffnet wird, dann sind alle vorher durchgeführten Definitionen (Funktionen und Variablen) verloren. Dies ist zwar im Jupyter-Notebook nicht der Fall, da das gesamte Notebook regelmäßig gespeichert wird, wenn jedoch ein längeres Programm notwendig wird, sollte dies besser mit einem Texteditor geschehen, um die Eingabe für den Interpreter vorzubereiten und dann mit dieser Datei als Eingabe den Interpreter starten. Diesen Prozess nennt man auch Erstellen eines Skripts. Wenn das Programm dann mit der Zeit immer länger wird, kann es auch in mehrere Dateien aufgeteilt werden, um insbesondere die Wartung zu erleichtern. Analog kann man auch Funktionen in eine Datei schreiben, die in mehreren Programmen verwendet werden, ohne dass ihre Definition in jedes Programm kopiert werden muss.

Um dies zu unterstützen, hat Python eine Möglichkeit, Definitionen (Funktionen, Variablen, Klassen) in eine Datei zu schreiben und diese Definitionen in einem Skript oder in einer interaktiven Instanz des Interpreters zu verwenden. Eine solche Datei heißt Modul. Definitionen aus einem Modul können in andere Module bzw. in das Modul __main__ importiert werden (Im Modul __main__ müssen alle Variablen vorhanden sein, auf die in einem auf der obersten Ebene und im Rechnermodus ausgeführten Skript zugegriffen werden soll).

Ein Modul ist eine Datei mit Python-Definitionen und Anweisungen. Der Dateiname ist der Modulname mit der Dateiendung .py. Innerhalb eines Moduls steht der Name des Moduls (als String) als Wert der globalen Variablen __name__ zur Verfügung. In einer Jupyter-Notebook Zelle kann eine Datei mit dem IPython-Magic-Befehl %%writefile fibo.py geschrieben werden, um eine Datei namens fibo.py im aktuellen Verzeichnis mit folgendem Inhalt zu erstellen:

In [2]:
%%writefile fibo.py
# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while b < n:
        result.append(b)
        a, b = b, a+b
    return result
Writing fibo.py

Jetzt kann mit dem Python-Befehl import dieses Modul importiert werden:

In [3]:
import fibo

Dieser Befehl importiert nicht die Namen der in fibo.py definierten Funktionen direkt in die aktuelle Symboltabelle sondern nur den Modulnamen fibo. Mit dem Modulnamen kann dann auf die Funktionen zugegriffen werden:

In [4]:
fibo.fib(1000)
print(fibo.fib2(100))
print(fibo.__name__)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
fibo

Falls eine Funktion oft verwendet wird, kann sie auch in eine lokale Variable abgespeichert werden:

In [5]:
fib = fibo.fib
fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 

Verwendung von Namen eines Moduls

Ein Modul kann ausführbare Anweisungen sowie Funktionsdefinitionen enthalten. Diese Anweisungen sind für die Initialisierung des Moduls vorgesehen. Sie werden nur beim ersten Mal ausgeführt, wenn der Modulname erstmalig in einer Import-Anweisung aufgerufen wird. (Sie werden natürlich auch ausgeführt, wenn die Modul-Datei als Skript ausgeführt wird.)

Jedes Modul hat seine eigene Symboltabelle, die als globale Symboltabelle von allen im Modul definierten Funktionen verwendet wird. So kann der Autor eines Moduls globale Variablen im Modul verwenden, ohne sich um versehentliche Zusammenstöße mit den globalen Variablen eines Benutzers zu kümmern. Auf der anderen Seite, wenn Sie wissen, was Sie tun, können Sie die globalen Variablen eines Moduls mit der gleichen Notation aufrufen, die verwendet wird, um auf die Funktionen des Moduls zu verweisen, z.B. also modulname.itemname.

Modules can import other modules. It is customary but not required to place all import statements at the beginning of a module (or script, for that matter). The imported module names are placed in the importing module’s global symbol table.

Module können andere Module importieren. Es ist üblich, aber nicht erforderlich, alle Import-Anweisungen am Anfang eines Moduls (oder Skripts) zu platzieren. Die importierten Modulnamen werden in der globalen Symboltabelle des importierenden Moduls platziert.

Es gibt eine Variante der Import-Anweisung, die Namen von einem Modul direkt in die Symboltabelle des importierenden Moduls importiert. Beispielsweise:

In [6]:
from fibo import fib, fib2
fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 

Diese Variante definiert jedoch nicht den Modulnamen, aus dem die Importe in der lokalen Symboltabelle aufgenommen werden (also ist in diesem Beispiel fibo nicht definiert).

Es gibt sogar eine Variante, um alle Namen zu importieren, die ein Modul definiert:

In [7]:
from fibo import *
fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 

Diese Variante importiert alle Namen außer denen, die mit einem Unterstrich (_) beginnen. In den meisten Fällen verwenden Python-Programmierer diese Möglichkeit nicht, da sie eine unbekannten Anzahl von Namen in den Interpreter einbringt und möglicherweise einige Dinge versteckt, die vorher bereits definiert waren und durch den import überschrieben werden.

Man beachte, dass im Allgemeinen die Praxis des Importes * aus einem Modul oder Paket verpönt ist, da es oft schlecht lesbaren Code verursacht. Allerdings ist es in Ordnung, es in einer interaktiven Sitzung zu benutzen, um die Schreibarbeit zu reduzieren.

Hinweis

Aus Effizienzgründen wird jedes Modul nur ein einziges Mal pro Interpretersitzung importiert. Wenn also eines der importierten Module geändert wird, muss der Interpreter neu gestartet werden bzw. in einem Jupyter Notebook der Kernel. Wenn ein Modul nur interaktiv getestet werden soll, dann kann auch importlib.reload() aus der Bibliothek importlib verwendet werden

In [8]:
import importlib
importlib.reload(fibo)
Out[8]:
<module 'fibo' from '/home/nik/Public/SE2017FS02/Skript/pre_chapter/Module/fibo.py'>

Module als Skripte ausführen

Wenn ein Python-Modul wie folgt aufgerufen wird

!python fibo.py <arguments>

wird der Code im Modul ausgeführt, genauso als ob er importiert worden wäre, allerdings mit dem Unterschied, dass die Variable name auf main gesetzt wird. Das bedeutet, dass durch Hinzufügen des folgenden Codes am Ende des Moduls:

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

der entsprechende if-Block ausgeführt wird, der die Befehlszeile analysiert und die Argumente in die Liste sys.argv schreibt und das Argument sys.argv[1] als Integer an die Funktion fib übergibt.

Damit kann die Modul-Datei sowohl als Skript als auch als importierbares Modul verwendet werden. Der entsprechende if-Block in dem obigen Code läuft ja nur, wenn das Modul als Skript ausgeführt wird:

In [9]:
%%writefile fibo2.py
# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while b < n:
        result.append(b)
        a, b = b, a+b
    return result

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))
Writing fibo2.py
In [10]:
!python fibo2.py 50
1 1 2 3 5 8 13 21 34 

Wenn das Modul importiert wird, wird der Code dagegen nicht ausgeführt:

In [11]:
import fibo2

Der obige Code mit der if-Abfrage wird häufig verwendet, um entweder eine bequeme Benutzeroberfläche zu einem Modul oder auch zu Testzwecken (das Ausführen des Moduls als Skript führt eine Test-Suite aus) bereitzustellen.

In [12]:
%%Mooc MoocStringAssessment
Out[12]:

Module - 1

In einer Datei m1.py ist die folgende Klasse c1 definiert:


class c1():
    def f1(self):
        print("Name der Klasse: {}".format(self.__class__))
        print("Name des Moduls: {}".format(self.__module__))
    def f2(self):
        print("Name der Funktion: {}".format(self.f2.__name__))

Geben sie den Code an, wie das Module m1 importiert wird:



In [13]:
%%Mooc MoocStringAssessment
Out[13]:

Module - 2

Verwenden sie das Modul m1 aus der obigen Aufgabe


Weisen sie eine Instanz der Klasse c1 der Variablen i1 zu:



In [14]:
%%Mooc MoocStringAssessment
Out[14]:

Module - 3

Verwenden sie wieder das Modul m1 aus der obigen Aufgabe


Geben sie den Code an, wie sie die Methode f1 der Instanz i1 der Klasse c1 aufrufen:



In [15]:
%%Mooc MoocStringAssessment
Out[15]:

Module - 4

In der obigen Datei m1.py wird die Funktion f2 wie folgt verändert:


class c1():
    def f1(self):
        print("Name der Klasse: {}".format(self.__class__))
        print("Name des Moduls: {}".format(self.__module__))
    def f2(self):
        print("Qual. Name der Funktion: {}".format(self.f2.__qualname__))

Geben sie das Ergebnis des Aufrufs der Funktion f2 aus der Instanz i1 an:



In [16]:
%%Mooc Video
Out[16]:

Weitere Literatur

In [17]:
%%Mooc WebReference

Modules

https://docs.python.org/3/tutorial/modules.html

Hinweis: Kapitel über Module und Pakete