Skip to content

6. Die Funktionen

Image

6.1. Skript [fonc_01]: Geltungsbereich von Variablen

Das Skript [fonc_01] zeigt Beispiele für den Gültigkeitsbereich von Variablen zwischen Funktionen:


# Gültigkeitsbereich der Variablen
def f1():
    # Die Verwendung globaler Variablen sollte vermieden werden
    # globale Variable i
    global i
    i += 1
    # lokale Variable j
    j = 10
    print(f"f1[i,j]=[{i},{j}]")


def f2():
    # Die Verwendung globaler Variablen ist zu vermeiden
    # globale Variable i
    global i
    i += 1
    # lokale Variable j
    j = 20
    print(f"f2[i,j]=[{i},{j}]")


def f3():
    # lokale Variable i
    i = 1
    # lokale Variable j
    j = 30
    print(f"f3[i,j]=[{i},{j}]")


# Hauptprogramm
i = 0
j = 0
# Diese beiden Variablen sind einer Funktion f
# nur dann bekannt sein, wenn diese mit der Anweisung „global“ ausdrücklich angibt, dass sie diese verwenden möchte
# oder die Funktion die globale Variable nur lesend verwendet
f1()
f2()
f3()
# j hat sich nicht geändert, aber i hat sich geändert
print(f"[i,j]=[{i},{j}]")

Ergebnisse


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_01.py
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[1,30]
[i,j]=[2,0]

Process finished with exit code 0

Anmerkungen:

  • Das Skript veranschaulicht die Verwendung der Variablen i, die in den Funktionen f1 und f2 global deklariert wurde. In diesem Fall nutzen das Hauptprogramm sowie die Funktionen f1 und f2 dieselbe Variable i.

6.2. Skript [fonc_02]: Geltungsbereich von Variablen

Das Skript [fonc_03] knüpft an das Skript [fonc_02] an und zeigt, wie die Verwendung globaler Variablen vermieden werden kann:


# Gültigkeitsbereich von Variablen
def f1(i):
    # lokale Variable i
    i += 1
    # lokale Variable j
    j = 10
    print(f"f1[i,j]=[{i},{j}]")
    # Der geänderte Wert wird zurückgegeben
    return i


def f2(i):
    # lokale Variable i
    i += 1
    # lokale Variable j
    j = 20
    print(f"f2[i,j]=[{i},{j}]")
    # der geänderte Wert wird zurückgegeben
    return i


def f3():
    # lokale Variable i
    i = 1
    # lokale Variable j
    j = 30
    print(f"f3[i,j]=[{i},{j}]")


# Hauptprogramm
i = 0
j = 0
# Diese beiden Variablen sind einer Funktion f
# nur dann bekannt, wenn diese mit der Anweisung „global“ ausdrücklich angibt, dass sie diese verwenden möchte
# oder wenn die Funktion die globale Variable nur lesend verwendet
i = f1(i)
i = f2(i)
f3()
# j hat sich nicht geändert, aber i hat sich geändert
print(f"[i,j]=[{i},{j}]")

Anmerkungen:

  • Zeilen 2, 12: Anstatt global deklariert zu werden, wird die Variable [i] als Parameter an die Funktionen f1 und f2 übergeben;
  • Zeilen 9, 19: Die Funktionen f1 und f2 geben die geänderte Variable [i] an das Hauptprogramm zurück. Dieses ruft sie in den Zeilen 36 und 37 ab;

Ergebnisse


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_02.py
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[1,30]
[i,j]=[2,0]

Process finished with exit code 0

6.3. Skript [fonc_03]: Geltungsbereich der Variablen

Das Skript [fonc_03] veranschaulicht eine Besonderheit der Variablen, die sowohl in einer Funktion als auch im aufrufenden Code verwendet werden, je nachdem, ob diese Variable in der Funktion ausschließlich lesbar ist oder nicht.


def f1():
    # hier ist die globale Variable i bekannt
    print(f"[f1] i={i}")
    # hier ist die globale Variable j bekannt
    print(f"[f1] j={j}")


def f2():
    # Hier ist die globale Variable i nicht bekannt
    # da die Funktion f2 eine gleichnamige lokale Variable definiert
    # dann hat diese Vorrang
    try:
        # Versuch, die weiter unten definierte lokale Variable i anzuzeigen
        print(f"[f2] i={i}")
        # Die folgende Anweisung macht „i“ zu einer lokalen Variablen der Funktion f2
        i = 7
    except BaseException as erreur:
        print(f"[f2] erreur={erreur}")


def f3():
    # Hier ist die globale Variable „i“ nicht bekannt
    # da die Funktion f3 eine gleichnamige lokale Variable definiert
    # diese hat dann Vorrang

    # Die folgende Anweisung definiert „i“ als lokale Variable
    i = 7
    # Ausgabe – hier ist „i“ bekannt
    print(f"[f3] i={i}")


# main -----------
# globale Variablen in Funktionen
i = 10
j = 20
# Aufruf von f1
f1()
print(f"[main] i={i}, j={j}")
# Aufruf von f2
f2()
print(f"[main] i={i}")
# Aufruf von f3
f3()
print(f"[main] i={i}")

Anmerkungen

  • Zeile 34: Der Hauptcode definiert eine Variable [i];
  • Zeilen 1–5: Die Funktion f1 verwendet ebenfalls eine Variable [i], ohne ihr einen Wert zuzuweisen. Es handelt sich um ein Auslesen der Variablen [i]. In diesem Fall wird die Variable [i] aus dem aufrufenden Code (Zeile 34) verwendet;
  • Zeilen 8–18: Die Funktion f2 verwendet ebenfalls eine Variable [i], weist ihr jedoch in Zeile 16 einen Wert zu. Durch die Zuweisung eines Werts an die Variable [i] in f2 wird [i] automatisch zu einer lokalen Variablen der Funktion [f2]. Diese „überdeckt“ somit die Variable [i] des aufrufenden Codes;
  • Zeile 14: Der Schreibvorgang für die lokale Variable [i] schlägt fehl, da diese bei Erreichen von Zeile 14 noch keinen Wert hat. Sie erhält ihren Wert erst in Zeile 16. Es wird eine Ausnahme ausgelöst. Aus diesem Grund wurde Zeile 14 in einen try/catch-Block eingefügt;
  • Zeilen 21–29: Die Funktion f3 macht dasselbe wie die Funktion f2, definiert jedoch ihre lokale Variable [i] früher;

Ergebnisse


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_03.py
[f1] i=10
[f1] j=20
[main] i=10, j=20
[f2] erreur=local variable 'i' referenced before assignment
[main] i=10
[f3] i=7
[main] i=10

Process finished with exit code 0

6.4. Skript [fonc_04]: Art der Parameterübergabe

Das Skript lautet wie folgt:


# Funktion f1
def f1(a):
    a = 2


# Funktion f2
def f2(a, b):
    a = 2
    b = 3
    return a, b


# ------------------------ main
x = 1
f1(x)
print(f"x={x}")
(x, y) = (-1, -1)
(x, y) = f2(x, y)
print(f"x={x}, y={y}")

Ergebnisse

1
2
3
4
5
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_04.py
x=1
x=2, y=3

Process finished with exit code 0

Anmerkungen:

  • In Python ist alles ein Objekt. Bestimmte Objekte werden als „unveränderlich“ (engl. „immutable“) bezeichnet: Sie können nicht verändert werden. Dies gilt für Zahlen, Zeichenketten und Tupel. Wenn Python-Objekte als Parameter an Funktionen übergeben werden, werden deren Referenzen übergeben, es sei denn, diese Objekte sind „unveränderlich“; in diesem Fall wird der Wert des Objekts übergeben;
  • Die Funktionen f1 (Zeile 2) und f2 (Zeile 7) sollen die Übergabe eines Ausgabeparameters veranschaulichen. Es soll erreicht werden, dass der tatsächliche Parameter einer Funktion durch die Funktion verändert wird;
  • Zeilen 2–3: Die Funktion f1 ändert ihren formalen Parameter a. Wir möchten wissen, ob auch der effektive Parameter geändert wird;
  • Zeilen 14–15: Der effektive Parameter lautet x=1. Zeile 2 der Ergebnisse zeigt, dass der effektive Parameter nicht verändert wird. Somit sind der effektive Parameter x und der formale Parameter a zwei verschiedene Objekte;
  • Zeilen 8–10: Die Funktion f2 ändert ihre formalen Parameter a und b und gibt sie als Ergebnisse zurück;
  • Zeilen 17–18: An f2 werden die effektiven Parameter (x, y) übergeben, und das Ergebnis von f2 wird in (x, y) zurückgespeichert. Zeile 3 der Ergebnisse zeigt, dass die effektiven Parameter (x, y) geändert wurden.

Daraus lässt sich schließen, dass „unveränderliche“ Objekte, die als Ausgabeparameter dienen, Teil der von der Funktion zurückgegebenen Ergebnisse sein müssen.

6.5. Skript [fonc_05]: Reihenfolge der Funktionen in einem Skript

Das Skript [fonc_05] zeigt, dass eine Funktion nicht aufgerufen werden kann, wenn sie zuvor im Code noch nicht aufgetreten ist:


# ------------------------ main
print(f2(100, 200))

# Funktion f1
def f1(a):
    return a + 10


# Funktion f2
def f2(a, b):
    return f1(a + b)

Hinweise

  • Zeile 2 führt zu einem Fehler, da sie die Funktion f2 verwendet, die im Skript noch nicht definiert wurde;

Ergebnisse

1
2
3
4
5
6
7
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_05.py
Traceback (most recent call last):
  File "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_05.py", line 2, in <module>
    print(f2(100, 200))
NameError: name 'f2' is not defined

Process finished with exit code 1

6.6. Skript [fonc_06]: Reihenfolge der Funktionen in einem Skript

Das Skript [fonc_06] zeigt, dass das, was für den aufrufenden Code gilt, nicht für die Funktionen gilt:


# Funktion f2
def f2(a, b):
    return f1(a + b)


# Funktion f1
def f1(a):
    return a + 10


# ------------------------ main
print(f2(100, 200))

Anmerkungen

  • Zeile 3: Die Funktion [f2] verwendet die Funktion [f1], die weiter unten im Skript definiert ist. Dies führt jedoch zu keinem Fehler. Daraus lässt sich schließen, dass die Reihenfolge der Funktionsdefinitionen in einem Python-Skript keine Rolle spielt;

Ergebnisse

1
2
3
4
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_06.py
310

Process finished with exit code 0

6.7. Skript [fonc_07]: Verwendung von Modulen

Das Skript [fonc_07] zeigt, wie Funktionen in einem Modul isoliert werden können.

Image

Wir kapseln wiederverwendbare Funktionen in einem Modul. Anstatt sie von einem Skript zum anderen zu übertragen,

  • legen wir sie in einer separaten Datei ab, die auf besondere Weise deklariert wird;
  • die Skripte, die diese Funktionen benötigen, „importieren“ das Modul, das sie enthält;

Das Skript [fonctions_module_01] lautet wie folgt:


# Funktion f2
def f2(a, b):
    return f1(a + b)

# Funktion f1
def f1(a):
    return a + 10

Damit die Funktionen des Skripts [fonctions_module_01] von anderen Skripten aufgerufen werden können, gibt es verschiedene Möglichkeiten. Diese unterscheiden sich je nachdem, ob das Skript innerhalb von [PyCharm] ausgeführt wird oder nicht.

Unter [PyCharm] werden die importierten Module in bestimmten Ordnern namens [Sources Root] gesucht. Es gibt zwei Möglichkeiten, einen Ordner zu einem [Sources Root] zu machen:

Image

  • In [4] hat der Ordner seine Farbe geändert;

Nach diesem Vorgang wird der Ordner „[fonctions/modules]“ als Quellordner erkannt. Man kann dann in einem Skript schreiben:

from fonctions_module_01 import f2

um die im Modul [fonctions_module_01.py] definierte Funktion f2 zu importieren bzw. zu verwenden.

Eine weitere Methode besteht darin, die Projekteigenschaften zu nutzen:

  • Oben ermöglicht die Sequenz [1-6], den Ordner [shared] als Ordner zum Ablegen der zu importierenden Module zu verwenden;

Wir werden vorerst außer dem Stammverzeichnis des Projekts keinen Ordner wie [Sources Root] deklarieren:

Image

Nachdem dies erledigt ist, können wir das folgende Skript [fonc-07] schreiben:


# Verwendung von Modulen
import sys

# ------------------------ main
print(f"Python path={sys.path}")
from fonctions.shared.fonctions_module_01 import f2

print(f2(100, 200))
  • Zeile 2: Das Objekt [sys] wird importiert, um in Zeile 5 dessen Attribut [path] nutzen zu können, das das sogenannte [Python Path] liefert: eine Liste von Ordnern, die auf der Suche nach importierten Modulen durchsucht werden;
  • Zeile 6: Man importiert die Funktion f2 aus dem Modul [fonctions_module_01]. Um dieses Modul anzugeben, verwendet man den Pfad, der vom Projektstammverzeichnis zum Modul führt. Bei PyCharm gehört das Projektstammverzeichnis immer zu den durchsuchten Ordnern, wenn in einem Skript nach einem importierten Modul gesucht wird. Dieser Ordner ist also Teil des [Python Path] des Projekts. Das können wir anhand von Zeile 5 überprüfen;
  • Zeile 6: Würde man den Pfad beschreiben, der vom Projektstammverzeichnis zum Ordner „[fonctions_module_01]“ führt, würde man „[fonctions/shared/fonctions_module_01]“ schreiben. Im Pfad eines Moduls wird das Zeichen „/“ durch einen Punkt ersetzt. Man schreibt also „[fonctions.modules.fonctions_module_01]“;
  • Nach Zeile 6 ist die Funktion f2 bekannt. Sie wird in Zeile 8 verwendet;

Ergebnisse


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_07.py
Python path=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
310

Process finished with exit code 0

Oben:

  • grün hervorgehoben, sieht man, dass das Projektstammverzeichnis Teil von [Python Path] ist;
  • gelb hervorgehoben ist zu sehen, dass der Ordner des ausgeführten Skripts ebenfalls Teil von [Python Path] ist;
  • die übrigen Elemente von [Python Path] stammen direkt aus dem Python-Installationsordner;

Was passiert, wenn man PyCharm nicht zum Ausführen von [fonc-07] verwendet?

Image

Image

  • Bei [1] wird das Skript [fonc-07] ausgeführt. Man befindet sich im Ordner [fonctions];
  • in [2] sieht man, dass der Ausführungsordner Teil von [Python Path] ist. Das ist immer so. Man sieht auch, dass der Stammordner [C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020] nicht Teil von [Python Path] ist;
  • in [3] meldet der Python-Interpreter, dass er das Modul [fonctions] nicht findet;

Um nach dem importierten Modul [fonctions.shared.fonctions_module_01] zu suchen, durchsucht der Python-Interpreter die Ordner von [Python Path] nach einem Unterordner namens [fonctions]. Er findet ihn nirgendwo. Tatsächlich befindet sich der Unterordner „[fonctions]“ im Ordner „[C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020]“, der nicht Teil von „[Python Path]“ ist.

Das Skript [fonc-08] bietet eine mögliche Lösung für dieses Problem.

6.8. Skript [fonc_08]: Ordner zu [Python Path] hinzufügen

Es ist möglich, das Skript [Python Path] programmgesteuert zu ändern, wie das Skript [fonc-08] zeigt:


# Verwendung von Modulen
import os
import sys

# Skriptverzeichnis
script_dir = os.path.dirname(os.path.abspath(__file__))
# Python-Pfad vor der Änderung
print(f"Python path avant={sys.path}")
# Der Ordner [shared] wird zum Python-Pfad hinzugefügt
sys.path.append(f"{script_dir}/shared")
# Python-Pfad nach der Änderung
print(f"Python path après={sys.path}")

# import f2
from fonctions_module_01 import f2

# ------------------------ main
print(f2(100, 200))

Hinweise

  • Zeile 4: Die spezielle Variable [__file__] ist der Name des Skripts, das ausgeführt wird. Je nach Ausführungskontext kann dieser Name absolut (PyCharm) oder relativ (Konsole) sein. Die Funktion [os.path.abspath] gibt den absoluten Namen der Datei zurück, deren Name ihr übergeben wird. Die Funktion [os.path.dirname] gibt den absoluten Namen des Ordners zurück, der die Datei enthält, deren Name ihr übergeben wird;
  • Zeile 10: [sys.path] ist ein Array, das die Namen der Ordner enthält, die bei der Suche nach einem Modul durchsucht werden sollen. Zu diesem Array wird das in Zeile 4 definierte Projektstammverzeichnis hinzugefügt;
  • [Python Path] wird vor (Zeile 8) und nach (Zeile 12) der Änderung angezeigt;
  • Zeile 15: Das Modul [fonctions_module_01], das die Funktion f2 enthält, wird importiert;

Die Ausführung in PyCharm liefert folgende Ergebnisse:


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_08.py
Python path avant=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
Python path après=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions/shared']
310

Process finished with exit code 0
  • Zeile 3: Man sieht, dass der Ordner „[shared]“ zweimal in „[Python Path]“ vorkommt. Das lässt sich vermeiden, stört hier aber nicht;
  • Zeile 4: Die Funktion f2 wurde erfolgreich ausgeführt;

Führen wir nun [fonc-08] in einem Terminal aus:


(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\fonctions>python fonc_08.py
Python path avant=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
Python path après=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions/shared']
310
  • Zeile 2: Wie zuvor befindet sich der Ordner „[shared]“ nicht in „[Python Path]“;
  • Zeile 3: Jetzt ist er darin enthalten;
  • Zeile 4: Die Funktion f2 wurde gefunden;

6.9. Skript [fonc_09]: Typdeklaration der Parameter

Das Skript [fonc_09] zeigt, dass man den Typ der Parameter einer Funktion sowie den des Ergebnisses deklarieren kann. Diese Deklaration dient jedoch lediglich der Dokumentation der Funktion. Der Python-Interpreter überprüft nicht, ob die tatsächlichen Parameter der Funktion tatsächlich den erwarteten Typ haben. PyCharm meldet jedoch Typinkonsistenzen zwischen tatsächlichen und formalen Parametern. Allein dieser Grund reicht aus, um Typdeklarationen unverzichtbar zu machen.

Das Skript lautet wie folgt:


# Eine Funktion mit Angabe des Parametertyps
# Dies dient lediglich der Dokumentation, da der Python-Interpreter dies nicht berücksichtigt


def show(param: int) -> int:
    print(f"param={param}, type(param)={type(param)}")
    return param + 1


# main -------------------------
print(show(4))
show("xyz")

Anmerkungen:

  • Zeile 5: Es wird deklariert, dass der formale Parameter [param] vom Typ [int] ist und dass das Ergebnis der Funktion ebenfalls vom Typ [int] ist;
  • Zeile 11: Der effektive Parameter der Funktion [show] hat den richtigen Typ;
  • Zeile 12: Der tatsächliche Parameter der Funktion [show] hat nicht den richtigen Typ;

Ergebnisse

C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_09.py
param=4, type(param)=<class 'int'>
5
param=xyz, type(param)=<class 'str'>
Traceback (most recent call last):
  File "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_09.py", line 11, in <module>
    show("xyz")
  File "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_09.py", line 6, in show
    return param + 1
TypeError: can only concatenate str (not "int") to str

Process finished with exit code 1
  • Zeile 10: Der Typ des Parameters [param] ist vom Typ [str]. Wenn diese Meldung angezeigt wird, befindet man sich bereits im Code der Funktion [show]. Der Python-Interpreter hat also akzeptiert, dass der tatsächliche Parameter der Funktion [show] vom Typ [str] ist;
  • Zeile 7 des Codes löst die Ausnahme aus, die in den Zeilen 4–10 der Ergebnisse dargestellt wird;

PyCharm weist jedoch auf eine Anomalie hin:

Image

In [1] hat PyCharm den fehlerhaften Aufruf hervorgehoben.

6.10. Skript [fonc_10]: benannte Parameter

Um Parameter an eine Funktion zu übergeben, können die Namen der formalen Parameter dieser Funktion verwendet werden. In diesem Fall muss die Reihenfolge der formalen Parameter nicht eingehalten werden:


# Die tatsächlichen Parameter können mit ihren formalen Namen bezeichnet werden
def f(x, y):
    return x + y


# main
print(f(y=10, x=3))

Anmerkungen

  • Zeile 2: Die Funktion f hat zwei formale Parameter x und y;
  • Zeile 7: Beim Aufruf der Funktion f können die Namen der formalen Parameter verwendet werden. Diese Vorgehensweise kann zumindest in zwei Fällen nützlich sein:
    • Die Funktion hat viele Parameter, von denen die meisten einen Standardwert haben. Beim Aufruf ermöglicht die oben beschriebene Technik, nur die Parameter zu initialisieren, für die man den Standardwert nicht verwenden möchte;
    • Wenn die formalen Parameter aussagekräftige Namen haben, verbessert die Verwendung benannter Parameter beim Aufruf der Funktion die Lesbarkeit des Codes;

Ergebnisse

1
2
3
4
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_10.py
13

Process finished with exit code 0

6.11. Skript [fonc_11]: rekursive Funktion

Das Skript [fonc_11] ist ein Beispiel für eine rekursive Funktion (die sich selbst aufruft):


# rekursive Funktion
def fact(i: int) -> int:
    # Fakultät(1) ist 1
    # Eine rekursive Funktion muss irgendwann enden
    if i == 1:
        return 1
    else:
        # Fakultät(i) = i * Fakultät(i-1)
        return i * fact(i - 1)


# ---------- main
print(f"fact(8)={fact(8)}")

Kommentare

  • Zeilen 1–9: die Fakultätsfunktion;
  • Zeile 9: Die Funktion [factorielle] ruft sich selbst auf;
  • Zeilen 5–6: Eine rekursive Funktion muss immer dann aufhören, wenn eine Bedingung erfüllt ist, da es sonst zu einer unendlichen Rekursion kommt;

Ergebnisse

1
2
3
4
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_11.py
fact(8)=40320

Process finished with exit code 0

6.12. Skript [fonc_12]: rekursive Funktion

Die Funktion [fonc_12] liefert weitere Details zur Funktionsweise der Rekursion:


# rekursive Funktion
# Verhalten des Parameters j


def fact(i: int, j: int) -> int:
    # Beendigung der rekursiven Funktion
    if i == 1:
        print(f"j={j}")
        return 1
    else:
        # j wird bearbeitet
        j += 1
        print(f"avant fact j={j}")
        # Rekursion
        f = fact(i - 1, j)
        print(f"après fact j={j}")
        # Ergebnis
        return i * f


# ---------- main
print(f"fact(8)={fact(8, 0)}")

Kommentare

  • Zeile 5: Wir beschäftigen uns weiterhin mit der Fakultätsfunktion. Wir fügen ihr den Parameter [j] hinzu;
  • Zeile 12: Die Variable j wird bei jeder Fakultätsberechnung regelmäßig erhöht. Ihr Wert wird vor (Zeile 12) und nach (Zeile 16) der Rekursion (Zeile 15) ausgegeben;

Ergebnisse

C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_12.py
avant fact j=1
avant fact j=2
avant fact j=3
avant fact j=4
avant fact j=5
avant fact j=6
avant fact j=7
j=7
après fact j=7
après fact j=6
après fact j=5
après fact j=4
après fact j=3
après fact j=2
après fact j=1
fact(8)=40320

Process finished with exit code 0
  • Zeilen 2–8: Man sieht, dass der Wert von [j] so lange ansteigt, wie die Rekursion fortgesetzt wird, bis die Bedingung erfüllt ist, bei der die Rekursion beendet wird. Ab diesem Zeitpunkt erfolgt die Rückgabe der Aufrufe der Funktion [fact] in umgekehrter Reihenfolge der Aufrufe;
  • Zeilen 10–16: Diese Ausgaben spiegeln die aufeinanderfolgenden Rückgaben des Aufrufs der Fakultätsfunktion wider. Die Variable [j] kehrt schrittweise zu ihrem Ausgangswert 1 zurück;