Zu Funktionsdefinitionen in Python (Zu Funktionsdefinitionen in Python), Lektion, Seite 724059
https://www.purl.org/stefan_ram/pub/zu_funktionsdefinitionen_python (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
Python-Kurs

Anmerkungen zu Funktionsdefinitionen in Python 

Begriffe

Funktionsdefinitionen werden umgangssprachlich auch manchmal ungenau als „Funktionen“ bezeichnet.

Eine Funktion  ist aber eigentlich eine Entität des Laufzeitmodells  (ein Funktionsobjekt), während eine Funktionsdefinition  eine Entität des Quelltextmodells ist (eine Anweisung).

Bei der Ausführung einer Funktionsdefinition wird zur Laufzeit ein entsprechendes Funktionsobjekt angelegt und an den in der Funktionsdefinition festgelegten Namen gebunden.

Aufruf nicht-existenter Funktionen

Es ist kein  Fehler, in einer Suite einen Namen zu verwenden, der zum Zeitpunkt der Definition gar nicht an ein Objekt gebunden ist, solange diese solch eine Bindung vor der ersten Auswertung jenes Namens  erfolgt.

Protokoll

def f():
g()

def g():
print( 'g' )

f()

g

Dies bedeutet aber auch, daß Tippfehler  in Namen von Funktionen oder Variablen erst bei der Auswertung  (also möglicherweise erst bei Kunden) gemeldet werden.

Einzeilige Funktionsdefinitionen

Es ist auch erlaubt, eine Anweisung in dieselbe Zeile hinter den Doppelpunkt zu schreiben. Auch mehrere Anweisung können hinter in derselben Zeile hinter dem Doppelpunkt stehen, die dann durch ein Semikolon »;« getrennt werden müssen. Falls mindestens eine Anweisung in derselben Zeile hinter dem Doppelpunkt steht, darf die Funktionsdefinition dann aber insgesamt nur eine Zeile umfassen.

Protokoll

def LKW(): print( "Lastkraftwagen" )

LKW()

Lastkraftwagen

ℛ Stilregel Die mehrzeilige Funktionsdefinition, bei der die Suite in einer neuen Zeilen beginnt, gilt in Python  als besserer Stil  verglichen mit dem Schreiben der Suite in die Zeile, welche mit »def« beginnt.

Funktionen, die keine Änderungen hervorrufen

Wenn man eine Funktion schreiben will, die nichts macht, verwendet man die Anweisung »pass«.

Protokoll
def NOP():
pass
Protokoll

NOP()

NOP()

(keine Änderung)

Eine Auswertungsanweisung, die keine Änderung hervorruft, hat in einer Funktionsdefinition ein ähnliche Bedeutung wie »pass«, anders als bei direkter Eingabe wird der Wert einer Auswertungsanweisung nicht  ausgegeben.

Protokoll

def NOP():
0

NOP()

(keine Änderung)

Für bestimmte Fälle, wie etwa „leere“ Funktionen, sollte jedoch »pass« verwendet werden. Dies macht die Absicht des Autors besser verständlich, da sich die Verwendung von »pass« für solche Fälle eingebürgert hat.

Eigenarten der Python -Konsole

Beendigung von Suiten in der Python -Konsole

Das folgende Skript ist als Skript in einer Quelldatei vollkommen korrekt.

Quelltext
def helloworld():
print( 'hello' )
helloworld()

Die Python-Konsole  verlangt allerdings eine Leerzeile, bevor nach einer eingerückten Eingabe wieder eine Eingabe ohne Einrückung akzeptiert wird. In der folgenden Konsoleneingabe findet sich eine Leerzeile hinter »print( 'hello' )«.

Konsoleneingabe
def helloworld():
print( 'hello' )


helloworld()

Das folgende Skript mit einer Leerzeile  hinter »def helloworld():« ist als Skript in einer Quelldatei vollkommen korrekt.

Quelltext
def helloworld():

print( 'hello' )
helloworld()

Die Python-Konsole  verbietet allerdings Leerzeilen  innerhalb eingerückter Einheiten.

Konsoleneingabe
def helloworld():
print( 'hello' )


helloworld()

Größere Skripte sollten auch wegen dieser Eigenarten der Konsole besser in Dateien  gehalten werden. Die Konsole ist für die Eingabe einzelner Zeilen oder notfalls auch kurzer Skripte geeignet.

Ausgaben in der Konsole

Werte von Auswertungsanweisungen werden in der Konsole ausgegeben. Diese Ausgabe erfolgt nicht mehr, wenn die Ausdrück in einer Funktion ausgewertet werden.

Eine Auswertungsanweisung  ist ein Ausdruck, der an einer Stelle verwendet wird, an der eine Anweisung erwartet wird.
Protokoll
22 + 1
23
Protokoll
def f():
22 + 1


f()
(keine Ausgabe)

Weder durch die Ausführung der def-Anweisung noch durch die Ausführung der Auswertungsanweisung »f()« wird der Name »_« an etwas gebunden.

Protokoll
def f():
print( 22 + 1 )


f()
23

Die Python -Konsole von IDLE 

Wenn ein Skript im IDLE -Skriptfenster ausgeführt wurde, dann können die vom Skript erzeugten Bindungen danach in der IDLE -Konsole verwendet werden. So können im IDLE -Skriptfenster definierte Funktionen danach auch in der IDLE -Konsole aufgerufen werden (wenn die Bindungen noch gelten). Nach einer Änderung im Skript muß dieses aber zunächst neu gestartet  werden, bevor sich die Änderungen auf die IDLE -Konsole auswirken können.

Zeichnen einer Flagge (Refaktor)

Flagge ohne Unterprogramme

from turtle import *

W = 99
D = 2*W

penup()

bgcolor( 0.7, 0.7, 0.7 )

left( 90 )
forward( W )
right( 90 )
backward( W*1.5 )
colormode( 255 )

fillcolor( 0x00, 0x55, 0xA4 )

begin_fill()
forward( W ); right( 90 );
forward( D ); right( 90 );
forward( W ); right( 90 );
forward( D ); right( 90 );
end_fill()
forward( W );

fillcolor( 0xFF, 0xFF, 0xFF )

begin_fill()
forward( W ); right( 90 );
forward( D ); right( 90 );
forward( W ); right( 90 );
forward( D ); right( 90 );
end_fill()
forward( W );

fillcolor( 0xEF, 0x54, 0x31 )

begin_fill()
forward( W ); right( 90 );
forward( D ); right( 90 );
forward( W ); right( 90 );
forward( D ); right( 90 );
end_fill()
forward( W );

hideturtle()

Flagge mit Unterprogrammen und Variablen

from turtle import *

W = 99
D = 2*W

def rect():
begin_fill()
forward( W ); right( 90 );
forward( D ); right( 90 );
forward( W ); right( 90 );
forward( D ); right( 90 );
end_fill()
forward( W )

penup()

bgcolor( 0.7, 0.7, 0.7 )

left( 90 )
forward( W )
right( 90 )
backward( W*1.5 )
colormode( 255 )

fillcolor( 0x00, 0x55, 0xA4 ); rect()
fillcolor( 0xFF, 0xFF, 0xFF ); rect()
fillcolor( 0xEF, 0x54, 0x31 ); rect()

hideturtle()

Namen von Funktoren (Stil)

Ein Funktor sollte einen nicht zu langen aussagekräftigen Namen  haben. Der Name des Funktors sollte im besten Fall schon alles über den Funktor sagen.

Es ist einfacher, einen guten Namen für einen Funktor zu finden wenn diese „nur eine Sache“ macht. Dann sagt man auch, der Funktor habe eine hohe Kohäsion.

Ein „und“ im Namen eines Funktors könnte ein Indiz dafür sein, daß der Funktor „zwei Sachen“ macht. Dann könnte es richtig sein, den Funktor in zwei  Funktoren zu zerlegen.

Ein Funktor, dessen Aufruf hauptsächlich für einen bestimmten Wert  steht, sollte nach diesem Wert  benannt werden. Der Name solch eines Funktors ist daher oft ein Substantiv  oder eine Nominalphrase. Man findet hier oft auch abgekürzte  Nominalphrasen: »len« („Länge“), »randint« („Zufallszahl“), »max« („Maximum“).

Ein Funktor, dessen Aufruf hauptsächlich eine bestimmte Aktivität  bewirkt, sollte nach dieser Aktivität  benannt werden. Der Name solch eines Funktors ist daher oft ein Verb  oder eine Verbalphrase  wie zum Beispiel »print« („drucke“).

Regel für Übungsaufgaben

Zur Lösung von Übungsaufgaben dürfen ab jetzt Funktionen („Hilfsfunktionen“) definiert und verwendet werden, auch wenn dies in der Aufgabenstellung nicht verlangt wird. (Die Definition dieser Funktionen wird damit auch ein Teil der Lösung und sollte dann beim Einreichen einer Lösung mit abgegeben werden.)

Zur Definition einer benannten  Funktion soll ab jetzt »def« verwendet werden und keine Lambda-Bindung. (Lambda-Funktionen sind hauptsächlich für die Verwendung als Argumente  gedacht, die Bindung eines Namens an eine Lambda-Funktion gilt als schlechter Stil.)

Lambda-Bindung Bindung einer Lambda-Funktion an einen Namen
Lambda-Funktion Wert eines Lamba-Ausdrucks
Lambda-Ausdruck mit »lambda« beginnender Ausdruck

Übungsaufgaben

/   Schildkröten

Schreiben Sie eine def-Funktionsdefinition für eine Funktion, die erst »pendown()« auswertet und dann ein kleines gleichseitiges Dreieck zeichnet.

Bewegen Sie die Schildkröte dann im Hauptprogramm nach einer Auswertung von »penup()« an verschiedene Stellen und rufen Sie die zuvor geschriebene Funktion auf, um an der jeweiligen Stelle ein gleichseitiges Dreieck zeichnen zu lassen.

The computer gives us words that do doug things. What daddy does is make new words to make computers easier to use."

The Mental Game of Python  - Raymond Hettinger  (PyBay 2019), 21′

“doug things” = “nerd things”? (In the online text based social medium “United Heroes MUSH”, Douglas "Doug" Ramsey is a nerd. “Doug was always a smarty, a bit of a nerd, good with computers and fond of science fiction and fantasy novels and role-playing games.”, “What Doug's power does, is actually rapid mental decryption.”)

/   Schildkröten (1) ⃗

Schreiben Sie eine def-Funktionsdefinition für eine Funktion, die ein kleines gleichseitiges Viereck zeichnet.

Bewegen Sie die Schildkröte dann an verschiedene Stellen und rufen Sie diese Funktion auf, um an der jeweiligen Stelle ein gleichseitiges Viereck zeichnen zu lassen.

/   Schildkröten (2) *

Schreiben Sie eine Funktion, welche die Schildkröte an eine zufällige Stellen bewegt und dann jeweils ein ihr als Argument übergebenes Objekt aufruft.

Rufen Sie diese Funktion dann jeweils einmal mit den folgenden Argumentwerten auf: 1.) eine Funktion, die ein kleines Dreieck zeichnet, 2.) eine Funktion, die ein kleines Rechteck zeichnet.

/   Verschachtelungen von Definitionen

main.py

def f():
print( 'f' )

def g():
f()

g()

Protokoll
f

In dem obigen Programm wird die Funktion »f« nur in der Definition von »g« aufgerufen.

In solch einem Fall kann die Definition von »f« auch direkt vor dem Aufruf in der Definition von »g« erfolgen!

Setzen Sie die Definition von »f« daher zu Übungszwecken einmal in die Definition von »g« ein!

Hierzu muß der Anfang der Definition von »f« soweit eingerückt sein, wie alle Anweisungen in der Suite von »g«, während der print-Aufruf weiterhin noch weiter eingerückt sein muß als der Beginn der Definition von »f«.

(Diese Verschachtelung von Funktionen sollte in der Praxis aber nur verwendet werden, wenn es einen besonderen Grund dafür gibt. Sonst sollte sie eher vermieden werden. Sie erfolgt hier nur, um das Schreiben von Verschachtelungen, das auch in weiteren Fällen hilfreich sein kann, zu üben.)

Der Typ von def-Funktion ⃗

Wir betrachten erneut die folgende Funktionsdefinition:

Protokoll
def LKW():
print( "Lastkraftwagen" )

Unsere Funktion hat den Typ »function«.

Protokoll
type( LKW )
<class 'function'>

Umbenennen von def-Funktionen ⃗

Protokoll

def LKW():
print( "Last", end = "" )
print( "kraftwagen" )

LKW()

Lastkraftwagen

Wir zeigen im folgenden die Umbenennung der definierten Funktion von »LKW« in »Lakrawa«.

Protokoll

Lakrawa = LKW

Lakrawa()

Lastkraftwagen
Protokoll

del LKW

Lakrawa()

Lastkraftwagen
Protokoll
LKW()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'LKW' is not defined
Protokoll

def LKW():

print( "Last", end = "" );

print( "kraftwagen" )

File "<stdin>", line 3

print( "kraftwagen" )

^

IndentationError: unindent does not match any outer indentation level

Protokoll

def LKW():

print( "Last", end = "" );

print( "kraftwagen" )

File "<stdin>", line 3

print( "kraftwagen" )

^

IndentationError: unexpected indent

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram724059 stefan_ram:724059 Zu Funktionsdefinitionen in Python Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd724059, slrprddef724059, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/zu_funktionsdefinitionen_python