(c) 2023 Technische Hochschule Augsburg - Fakultät für Informatik - Prof.Dr.Nik Klever - Impressum
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:
%%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:
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:
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:
fib = fibo.fib
fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
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:
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:
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
import importlib
importlib.reload(fibo)
<module 'fibo' from '/home/nik/Public/SE2017FS02/Skript/pre_chapter/Module/fibo.py'>
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:
%%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
!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:
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.
%%Mooc MoocStringAssessment
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__))
%%Mooc MoocStringAssessment
Verwenden sie das Modul m1 aus der obigen Aufgabe
%%Mooc MoocStringAssessment
Verwenden sie wieder das Modul m1 aus der obigen Aufgabe
%%Mooc MoocStringAssessment
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__))
%%Mooc Video
%%Mooc WebReference