Funktionen kompakt: Funktionen strukturieren Programme und machen Code wiederverwendbar. Dieses Kapitel behandelt def, return, Standard- und Schlüsselwortargumente, *args, **kwargs sowie lokale und globale Namen.

Zusätzlich wird die moderne Syntax für positionsgebundene (/) und reine Schlüsselwortparameter (*) erläutert.

Funktionen

Syntax

Functions

Das Konzept einer Funktion ist eines der wichtigsten in der Mathematik. Eine übliche Verwendung von Funktionen in Computersprachen ist die Implementierung mathematischer Funktionen. Eine solche Funktion berechnet ein oder mehrere Ergebnisse, die vollständig durch die an sie übergebenen Parameter bestimmt werden.

Das ist Mathematik, aber wir sprechen über Programmierung und Python. Was ist also eine Funktion in der Programmierung? Im allgemeinsten Sinne ist eine Funktion ein Strukturierungselement in Programmiersprachen, um eine Reihe von Anweisungen zu gruppieren, damit sie in einem Programm mehr als einmal verwendet werden können. Die einzige Möglichkeit, dies ohne Funktionen zu erreichen, besteht darin, Code durch Kopieren und Anpassen an verschiedene Kontexte wiederzuverwenden, was eine schlechte Idee wäre. Redundanter Code - in diesem Fall sich wiederholender Code - sollte vermieden werden! Die Verwendung von Funktionen verbessert normalerweise die Verständlichkeit und Qualität eines Programms. Dies senkt auch die Kosten für die Entwicklung und Wartung der Software.

Je nach Programmiersprache und Kontext begegnet man verwandten Begriffen wie Unterprogramm, Routine, Prozedur oder Methode. In Python bezeichnet Methode speziell eine Funktion, die über eine Klasse bzw. ein Objekt aufgerufen wird.

Moderne Funktionssignaturen: Python kann gezielt festlegen, wie Argumente übergeben werden. Parameter vor / sind positional-only, Parameter nach einem alleinstehenden * keyword-only. Beispiel: def skaliere(x, /, *, faktor=1): return x * faktor. Der Aufruf skaliere(10, faktor=2) ist gültig; skaliere(x=10, faktor=2) nicht. Typannotationen wie def addiere(a: int, b: int) -> int: dokumentieren erwartete Typen und unterstützen Werkzeuge zur statischen Analyse, werden von Python zur Laufzeit aber nicht automatisch erzwungen.

Ein motivierendes Beispiel für Funktionen

Schauen wir uns das folgende Beispiel an:

print("Das Programm startet")

print("Hallo Peter")
print("Schön dich zu sehen!")
print("Viel Spaß mit dem Programm!")

# hier stelle man sich irgendwelchen Code vor:
egal = "über dies nicht nachdenken"
ist_nicht_wichtig = "normalerweise schon"

print("Hallo Dora")
print("Schön dich zu sehen!")
print("Viel Spaß mit dem Programm!")

# irgendein Code:
wie_auch_immer = "mir auch "
x = "steht stellvertretend"
y = "stellvertretend für wichtigen Code"

print("Hallo Kevin")
print("Schön dich zu sehen!")
print("Viel Spaß mit dem Programm!")
Das Programm startet
Hallo Peter
Schön dich zu sehen!
Viel Spaß mit dem Programm!
Hallo Dora
Schön dich zu sehen!
Viel Spaß mit dem Programm!
Hallo Kevin
Schön dich zu sehen!
Viel Spaß mit dem Programm!

Schauen wir uns den obigen Code genauer an:

gleiche Blöcke

Wir können im Code sehen, dass wir drei Personen begrüßen. Jedes Mal verwenden wir drei print-Aufrufe, die nahezu gleich sind. Nur der Name ist anders. Dies nennen wir redundanten Code. Wir wiederholen den Code dreimal. Das sollte natürlich nicht sein. Dies ist der Punkt, an dem Funktionen in Python verwendet werden können und sollten. Wir könnten im Code statt der Namen einen Platzhalter verwenden. Im folgenden ein Puzzleteil. Wir schreiben den Code nur noch einmal und ersetzen jeweils das Puzzleteil mit Namen:

Code mit Schablone

Das war natürlich noch kein korrekter Python-Code. Wie dies in Python geht zeigen wir im folgenden Abschnitt.

Funktionen in Python

Der folgende Code verwendet eine Funktion. Das vorherige Puzzleteil ist jetzt ein Parameter mit dem Namen name:

def begruesse(name):
    print("Hallo " + name)
    print("Schön dich zu sehen!")
    print("Viel Spaß mit dem Programm!")

    
print("Das Programm startet")

begruesse("Peter")

# hier stelle man sich irgendwelchen Code vor:
egal = "über dies nicht nachdenken"
ist_nicht_wichtig = "normalerweise schon"

begruesse("Dora")

# irgendein Code:
wie_auch_immer = "mir auch "
x = "steht stellvertretend"
y = "stellvertretend für wichtigen Code"

begruesse("Kevin")
Das Programm startet
Hallo Peter
Schön dich zu sehen!
Viel Spaß mit dem Programm!
Hallo Dora
Schön dich zu sehen!
Viel Spaß mit dem Programm!
Hallo Kevin
Schön dich zu sehen!
Viel Spaß mit dem Programm!

Im vorigen Code benutzten wir eine Python-Funktion. Wir können sehen, dass eine Funktionsdefinition mit dem def-Schlüsselwort eingeleitet wird. Die allgemeine Syntax sieht folgendermaßen aus:

def funktionsname(parameterliste):
    Anweisungen, d. h. der Funktionskörper

Die Parameterliste besteht aus keinem oder mehreren Parametern. Parameter werden als Argumente bezeichnet, wenn die Funktion aufgerufen wird. Der Funktionskörper besteht aus eingerückten Anweisungen. Der Funktionskörper wird bei jedem Aufruf der Funktion ausgeführt. Wir zeigen dies im folgenden Bild:

Function Call: Control Flow

Der Code aus dem Bild ist im Folgenden zu sehen:

def f(x, y):
    z = 2 * (x + y)
    return z


print("Programm fängt an!")
a = 3
res1 = f(a, 2+a)
print("Ergebnis des Funktionsaufrufs: ", res1)
a = 4
b = 7
res2 = f(a, b)
print("Ergebnis des Funktionsaufrufs: ", res2)
Programm fängt an!
Ergebnis des Funktionsaufrufs:  16
Ergebnis des Funktionsaufrufs:  22

Wir rufen die Funktion zweimal im Programm auf. Die Funktion hat zwei Parameter, die x und y heißen. Dies bedeutet, dass die Funktion f zwei Werte erwartet, oder ich sollte" zwei Objekte "sagen. Zunächst rufen wir diese Funktion mit f (a, 2 + a) auf. Dies bedeutet, dass a zu x geht und das Ergebnis von 2 + a (5) 'zu' der Variablen y geht. Der Mechanismus zum Zuweisen von Argumenten zu Parametern wird als ** Argumentübergabe ** bezeichnet. Wenn wir die Anweisung return erreichen, wird das von z referenzierte Objekt zurückgegeben, was bedeutet, dass es der Variablen res1 zugewiesen wird. Nach Verlassen der Funktion f werden die Variable z und die Parameter x und y automatisch gelöscht.

Function Call: Argument Passing Part1

Die Verweise auf die Objekte sind im nächsten Diagramm zu sehen:

Function Call: Argument Passing Part2

Der nächste Python-Codeblock enthält ein Beispiel für eine Funktion ohne return-Anweisung. Wir verwenden die pass Anweisung innerhalb dieser Funktion. pass ist eine Nulloperation. Dies bedeutet, dass bei der Ausführung nichts passiert. Es ist nützlich als Platzhalter in Situationen, in denen eine Anweisung syntaktisch erforderlich ist, aber kein Code ausgeführt werden muss:

def doNothing():
     pass



Eine nützlichere Funktion:

def fahrenheit(T_in_celsius):
    """ Gibt die Temperatur T_in_celsius in Grad Fahrenheit zurück """
    return (T_in_celsius * 9 / 5) + 32

for t in (22.6, 25.8, 27.3, 29.8):
    print(t, ": ", fahrenheit(t))
22.6 :  72.68
25.8 :  78.44
27.3 :  81.14
29.8 :  85.64

""" Gibt die Temperatur in Grad Fahrenheit zurück """ ist der sogenannte Docstring. Er wird bei der help-Funktion verwendet:

help(fahrenheit)
Help on function fahrenheit in module __main__:

fahrenheit(T_in_celsius)
    Gibt die Temperatur T_in_celsius in Grad Fahrenheit zurück

Der Docstring hängt an dem Attribut __doc__:

fahrenheit.__doc__
Ausgabe:
' Gibt die Temperatur T_in_celsius in Grad Fahrenheit zurück '

Standardargumente in Python

Wenn wir eine Python-Funktion definieren, können wir einen Standardwert für einen Parameter festlegen. Wenn die Funktion ohne das Argument aufgerufen wird, wird dieser Standardwert dem Parameter zugewiesen. Dies macht einen Parameter optional. Mit anderen Worten: Standardparameter sind Parameter, die beim Aufruf der Funktion nicht angegeben werden müssen. In diesem Fall werden die Standardwerte verwendet.

Wir werden das Funktionsprinzip von Standardparametern anhand eines einfachen Beispiels demonstrieren. Die folgende Funktion Hallo - die nicht sehr nützlich ist - begrüßt eine Person. Wenn kein Name angegeben wird, werden alle begrüßt:

def hallo(name="zusammen"):
    """ Grüßt eine Person """
    print("Hallo " + name + "!")

hallo("Peter")
hallo()
Hallo Peter!
Hallo zusammen!
def hello(name="Bruce"):
    """ Grüßt eine Person """
    print("Hello " + name + "!")

hello("Peter")
hello()
Hello Peter!
Hello Bruce!

Veränderliche Standardargumente

Standardwerte werden ausgewertet, wenn die def-Anweisung ausgeführt und damit die Funktion definiert wird, nicht bei jedem späteren Funktionsaufruf. Das ist besonders wichtig bei veränderbaren Objekten wie Listen oder Dictionaries.

Wird beispielsweise eine Liste direkt als Standardwert verwendet, teilen sich alle Aufrufe dieselbe Liste. Das führt häufig zu unerwarteten Ergebnissen. Wenn bei jedem Aufruf eine neue Liste entstehen soll, verwendet man üblicherweise None als Sentinel und erzeugt die Liste im Funktionskörper:

def spammer(tuete=None):
    if tuete is None:
        tuete = []
    tuete.append("spam")
    return tuete

Schauen wir zunächst, wie der problematische Fall mit einem veränderbaren Standardwert aussieht:

def spammer(tüte=[]):
    tüte.append("spam")
    return tüte

Wenn Sie diese Funktion einmal ohne Argument aufrufen, wird das erwartete Ergebnis zurückgegeben:

spammer()
Ausgabe:
['spam']

Die Überraschung zeigt, wenn wir die Funktion ohne Argument erneut aufrufen:

spammer()
Ausgabe:
['spam', 'spam']

Die meisten Programmierer haben das gleiche Ergebnis wie beim ersten Aufruf erwartet, d. H. "[" Spam "]" "

Um zu verstehen, was los ist, müssen Sie wissen, was passiert, wenn die Funktion definiert wird. Der Compiler erstellt ein Attribut __defaults__:

def spammer(tüte=[]):
    tüte.append("spam")
    return tüte

spammer.__defaults__
Ausgabe:
([],)

Wann immer wir die Funktion aufrufen, wird der Parameter bag dem Listenobjekt zugewiesen, auf das Spammer .__ Defaults __ [0] verweist:

for i in range(5):
    print(spammer())
    
print("spammer.__defaults__", spammer.__defaults__)
['spam']
['spam', 'spam']
['spam', 'spam', 'spam']
['spam', 'spam', 'spam', 'spam']
['spam', 'spam', 'spam', 'spam', 'spam']
spammer.__defaults__ (['spam', 'spam', 'spam', 'spam', 'spam'],)

Jetzt wissen und verstehen Sie, was los ist, aber Sie fragen sich vielleicht, wie Sie dieses Problem lösen können. Die Lösung besteht darin, den unveränderlichen Wert None als Standard zu verwenden. Auf diese Weise kann die Funktion bag dynamisch (zur Laufzeit) auf eine leere Liste setzen:

def spammer(tüte=None):
    if tüte is None:
        tüte = []
    tüte.append("spam")
    return tüte

for i in range(5):
    print(spammer())
    
print("spammer.__defaults__", spammer.__defaults__)
['spam']
['spam']
['spam']
['spam']
['spam']
spammer.__defaults__ (None,)

Docstrings

Ein Docstring ist eine String-Literal-Anweisung als erste Anweisung im Funktionskörper. Python speichert diesen Dokumentationstext im Attribut funktion.__doc__; Werkzeuge wie help() können ihn anzeigen.

Beispiel:

def hallo(name="zusammen"):
    """ Grüßt einer Person """
    print("Hallo " + name + "!")

print("Die Docstring der Funktion Hallo:" + hallo.__doc__)
Die Docstring der Funktion Hallo: Grüßt einer Person 

Schlüsselwortargumente

Bei einem Funktionsaufruf können viele Parameter entweder über ihre Position oder explizit über ihren Namen belegt werden. Ein benannt übergebener Wert heißt keyword argument (Schlüsselwortargument). Dadurch können Aufrufe lesbarer werden und optionale Parameter gezielt gesetzt werden.

Ein Beispiel:

def sumsub(a, b, c=0, d=0):
    return a - b + c - d

print(sumsub(12, 4))
print(sumsub(42, 15, d=10))
8
17

Ein Parameter darf bei einem Aufruf nicht gleichzeitig positional und per Schlüsselwort belegt werden; ansonsten erhält er zwei Werte und Python meldet einen TypeError. Abgesehen von ausdrücklich positional-only deklarierten Parametern können normale Parameter aber grundsätzlich auch per Schlüsselwort übergeben werden.

Im Beispiel können wir d gezielt setzen und für c den Standardwert beibehalten. Ohne Schlüsselwortargument müssten wir den Wert für c ausdrücklich angeben:

print(sumsub(42,15,0,10))
17

Rückgabewerte

In unseren vorherigen Beispielen haben wir eine return-Anweisung in der Funktion sumsub verwendet, jedoch nicht in Hello. Wir können also sehen, dass eine return-Anweisung nicht zwingend erforderlich ist. Aber was wird zurückgegeben, wenn wir nicht explizit eine return-Anweisung geben. Mal schauen:

def no_return(x, y):
    c = x + y

res = no_return(4, 5)
print(res)
None

Wenn wir dieses kleine Skript starten, wird None gedruckt, d. H. Der spezielle Wert None wird von einer Funktion ohne Rückgabe zurückgegeben. None wird auch zurückgegeben, wenn wir nur eine Rückgabe in einer Funktion ohne Ausdruck haben:

def empty_return(x, y):
    c = x + y
    return

res = empty_return(4, 5)
print(res)
None

Andernfalls wird der Wert des Ausdrucks nach der Rückgabe zurückgegeben. Im nächsten Beispiel wird 9 gedruckt:

def return_sum(x, y):
    c = x + y
    return c

res = return_sum(4, 5)
print(res)
9

Fassen wir dieses Verhalten zusammen: Funktionskörper können eine oder mehrere return-Anweisungen enthalten. Sie können sich überall im Funktionskörper befinden. Eine return-Anweisung beendet die Ausführung des Funktionsaufrufs und "gibt" das Ergebnis, d. H. Den Wert des Ausdrucks nach dem Schlüsselwort return, an den Aufrufer zurück. Wenn die return-Anweisung keinen Ausdruck enthält, wird der spezielle Wert None zurückgegeben. Wenn der Funktionscode keine return-Anweisung enthält, endet die Funktion, wenn der Kontrollfluss das Ende des Funktionskörpers erreicht und der Wert None zurückgegeben wird.

Mehrere Werte zurückgeben

Eine Funktion kann genau einen Wert zurückgeben, oder wir sollten besser ein Objekt sagen. Ein Objekt kann ein numerischer Wert sein, z. B. eine Ganzzahl oder ein Gleitkommawert. Es kann aber auch z.B. eine Liste oder ein Wörterbuch. Wenn wir also beispielsweise 3 Ganzzahlwerte zurückgeben müssen, können wir eine Liste oder ein Tupel mit diesen drei Ganzzahlwerten zurückgeben. Das heißt, wir können indirekt mehrere Werte zurückgeben. Das folgende Beispiel, das die Fibonacci-Grenze für eine positive Zahl berechnet, gibt ein 2-Tupel zurück. Das erste Element ist die größte Fibonacci-Zahl kleiner als x und die zweite Komponente ist die kleinste Fibonacci-Zahl größer als x. Der Rückgabewert wird sofort durch Auspacken in die Variablen lub und sup gespeichert:

def fib_intervall(x):
    """ gibt die größten Fibonacci zurück
     Zahl kleiner als x und die niedrigste
     Fibonacci-Zahl höher als x"""
    if x < 0:
        return -1
    (alt,neu) = (0,1)
    while True:
        if neu < x:
            (alt,neu) = (neu,alt+neu)
        else:
            if neu == x: 
                neu = alt+neu
            return (alt, neu)
            
while True:
    x = int(input("Ihre Nummer: "))
    if x <= 0:
        break
    (lub, sup) = fib_intervall(x)
    print("Größte Fibonacci-Zahl kleiner als x: " + str(lub))
    print("Kleinste Fibonacci-Zahl größer als x: " + str(sup))
Größte Fibonacci-Zahl kleiner als x: 4181
Kleinste Fibonacci-Zahl größer als x: 6765

Lokale und globale Variablen in Funktionen

Variablennamen sind standardmäßig lokal für die Funktion, in der sie definiert werden.

def f(): 
    print(s)
s = "Python"
f()
Python
def f(): 
    s = "Perl"
    print(s)
f()
Perl
s = "Python"
f()
print(s)
Perl
Python
def f(): 
    print(s)
    s = "Perl"
    print(s)


s = "Python" 
f()
print(s)
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-64-81b2fbbc4d42> in <module>
      6 
      7 s = "Python"
----> 8 f()
      9 print(s)

<ipython-input-64-81b2fbbc4d42> in f()
      1 def f():
----> 2     print(s)
      3     s = "Perl"
      4     print(s)
      5 

UnboundLocalError: local variable 's' referenced before assignment

Die Fehlermeldung entsteht, weil Python bereits beim Kompilieren des Funktionskörpers erkennt, dass s innerhalb von f() zugewiesen wird. Ohne eine global- oder nonlocal-Deklaration gilt s deshalb in der gesamten Funktion als lokaler Name. Beim ersten print(s) besitzt diese lokale Variable aber noch keinen Wert, daher entsteht ein UnboundLocalError.

def f():
    global s
    print(s)
    s = "Hund"
    print(s) 
s = "Katze" 
f()
print(s)
Katze
Hund
Hund

Wir haben die Variable innerhalb des Skripts global gemacht. Daher wird alles, was wir innerhalb des Funktionskörpers von f mit s tun, mit der globalen Variablen s außerhalb von f gemacht.

Beliebige Anzahl von Parametern

Es gibt viele Situationen in der Programmierung, in denen die genaue Anzahl der erforderlichen Parameter nicht a priori bestimmt werden kann. In Python kann eine variable Anzahl positionaler Argumente mit *args aufgenommen werden. Innerhalb der Funktion ist args ein Tupel. Ein Sternchen * steht dabei vor dem Parameternamen. Dieses Sternchen sollte nicht mit der C-Syntax verwechselt werden, bei der diese Notation mit Zeigern verbunden ist. Beispiel:

def arithmetisches_mittel(erste, *werte):
    """ Diese Funktion berechnet das arithmetische Mittel eines nicht leeren
         beliebige Anzahl von Zahlenwerten """

    return (erste + sum(werte)) / (1 + len(werte))

print(arithmetisches_mittel(45,32,89,78))
print(arithmetisches_mittel(8989.8,78787.78,3453,78778.73))
print(arithmetisches_mittel(45,32))
print(arithmetisches_mittel(45))
61.0
42502.3275
38.5
45.0

Das ist großartig, aber wir haben immer noch ein Problem. Möglicherweise haben Sie eine Liste mit numerischen Werten. Wie zum Beispiel,

 x = [3, 5, 9] 

Sie können es nicht mit anrufen

 
arithmetisches_mittel (x) 

weil "arithmetisches_mittel" mit einer Liste nicht fertig wird. Ich nenne es mit

 
arithmetisches_mittel (x [0], x [1], x [2]) 

ist umständlich und vor allem innerhalb eines Programms unmöglich, da die Liste beliebig lang sein kann.

Die Lösung ist einfach. Wir fügen einen Stern vor dem x hinzu, wenn wir die Funktion aufrufen.

 
arithmetisches_mittel (* x) 

Dadurch wird die Liste "entpackt" oder vereinzelt.

Ein praktisches Beispiel: Wir haben eine Liste von 4, 2-Tupel-Elementen:

 meine_liste = [('a', 232), 
           ('b', 343), 
           ('c', 543), 
           ('d', 23)] 

Wir möchten diese Liste in die folgende Liste mit 2 Elementen und 4 Tupeln umwandeln:

 [('a', 'b', 'c', 'd'), 
 (232, 343, 543, 23)] 

Dies kann mithilfe des * -Operators und der Zip-Funktion folgendermaßen erfolgen:

 Liste (zip (* meine_liste)) 


Beliebige Anzahl von Schlüsselwortparametern

Im vorherigen Kapitel haben wir gezeigt, wie eine beliebige Anzahl von Positionsparametern an eine Funktion übergeben wird. Es ist auch möglich, eine beliebige Anzahl von Schlüsselwortparametern an eine Funktion als Wörterbuch zu übergeben. Zu diesem Zweck müssen wir das doppelte Sternchen "**" verwenden.

def f(**kwargs):
    print(kwargs)
f()
{}
f(de="Deutsch",en="Englisch",fr="Franzözisch")
{'de': 'Deutsch', 'en': 'Englisch', 'fr': 'Franzözisch'}

Ein Anwendungsfall ist der folgende:

def f(a, b, x, y):
    print(a, b, x, y)
d = {'a':'append', 'b':'block','x':'extract','y':'yes'}
f(**d)
append block extract yes

Übungen mit Funktionen

Übung 1

Im Kapitel ,,Bedingte Anweisungen hatten wir ein Beispielprogramm, in dem wir ein Hundealter in Menschenalter mit folgenden Regeln umgerechnet hatten:

  • Ein einjähriger Hund entspricht in etwa einem 14-jährigen Menschen
  • Ein Hund der zwei Jahre alt ist, entspricht entwicklungsmäßig einem 22-jährigen Menschen.
  • Jedes weitere Hundejahr entspricht fünf Menschenjahre.

Schreiben Sie nun eine Funktion für diese Umwandlung.

Übung 2

Schreiben Sie eine Funktion, die einen Text aufnimmt und mit einer Caesar-Chiffre verschlüsselt. Dies ist eine der einfachsten und am häufigsten bekannten Verschlüsselungstechniken. Jeder Buchstabe im Text wird durch einen Buchstaben ersetzt, der eine feste Anzahl von Stellen weiter im Alphabet enthält.

Was ist mit dem Entschlüsseln des codierten Textes?

Die Caesar-Chiffre ist eine Substitutions-Chiffre.

caesar cipher

Übung 3

Wir können eine weitere Substitutions-Chiffre erstellen, indem wir den Propheten permutieren und die Buchstaben dem entsprechenden permutierten Alphabet zuordnen.

Schreiben Sie eine Funktion, die einen Text und ein Wörterbuch benötigt, um den angegebenen Text mit einem permutierten Alphabet zu entschlüsseln oder zu verschlüsseln.

Übung 4

Schreiben Sie eine Funktion txt2morse, die einen Text in Morsecode übersetzt, d. H. Die Funktion gibt eine Zeichenfolge mit dem Morsecode zurück.

Schreiben Sie eine weitere Funktion morse2txt, die eine Zeichenfolge im Morsecode in eine „normale“ Zeichenfolge übersetzt.

Die Morsezeichen sind durch Leerzeichen getrennt. Wörter mit drei Leerzeichen.

International Morse Code

Übung 5

Vielleicht ist der erste Algorithmus, der zur Approximation von $ \ sqrt {S} $ verwendet wird, als "babylonische Methode" bekannt, benannt nach den Babyloniern, oder "Heldenmethode", benannt nach dem griechischen Mathematiker Hero of Alexandria aus dem ersten Jahrhundert, der den ersten expliziten gab Beschreibung der Methode.

Wenn eine Zahl $ x_n $ nahe an der Quadratwurzel von $ a $ liegt, dann $$ x_ {n + 1} = \ frac {1} {2} (x_n + \ frac {a} {x_n}) $$ wird eine bessere Annäherung sein.

Schreiben Sie ein Programm, um die Quadratwurzel einer Zahl nach der babylonischen Methode zu berechnen.

Übung 6

Schreiben Sie eine Funktion, die die Position des n-ten Auftretens von a berechnet String Sub in einem anderen String s. Wenn sub in s nicht vorkommt, wird -1 zurückgegeben.

Lösungen

Lösung zu Übung 1

def dog_age2human_age(dog_age):
    """dog_age2human_age(dog_age)"""
    if dog_age == 1:
        human_age = 14
    elif dog_age == 2:
        human_age = 22
    else:
        human_age =  22 + (dog_age-2)*5
    return human_age

age = int(input("Wie alt ist dein Hund? "))
print(f"Enspricht {dog_age2human_age(age)} Menschenjahren")
Enspricht 37 Menschenjahren

Lösung zu Übung 2

import string
abc = string.ascii_uppercase
def caesar(txt, n, coded=False):
    """ Gibt den codierten oder decodierten Text zurück """
    result = ""
    for char in txt.upper():
        if char not in abc:
            result += char
        elif coded:
            result += abc[(abc.find(char) + n) % len(abc)]
        else:
            result += abc[(abc.find(char) - n) % len(abc)]
    return result

n = 3
x = caesar("Hallo, hier bin ich!", n)
print(x)
print(caesar(x, n, True))
EXIIL, EFBO YFK FZE!
HALLO, HIER BIN ICH!

In der vorherigen Lösung ersetzen wir nur die Buchstaben. Jedes Sonderzeichen bleibt unberührt. Die folgende Lösung fügt einige Sonderzeichen hinzu, die ebenfalls permutiert werden. Spezielle Zeichen, die nicht in abc enthalten sind, gehen bei dieser Lösung verloren!

import string
abc = string.ascii_uppercase + " .,-?!"
def caesar(txt, n, coded=False):
    """ Gibt den codierten oder decodierten Text zurück """
    result = ""
    for char in txt.upper():
        if coded:
            result += abc[(abc.find(char) + n) % len(abc)]
        else:
            result += abc[(abc.find(char) - n) % len(abc)]
    return result

n = 3
x = caesar("Hallo, hier bin ich!", n)
print(x)
print(caesar(x, n, True))
E-IILZXEFBOX?FKXF!E,
HALLO, HIER BIN ICH!

Lösung zu Übung 3

import string
from random import sample

alphabet = string.ascii_letters
permutated_alphabet = sample(alphabet, len(alphabet))

encrypt_dict = dict(zip(alphabet, permutated_alphabet))
decrypt_dict = dict(zip(permutated_alphabet, alphabet))

def encrypt(text, edict):
    """ Every character of the text 'text'
    is mapped to the value of edict. Characters
    which are not keys of edict will not change"""
    res = ""
    for char in text:
        res = res + edict.get(char, char)
    return res

# Donald Trump: 5:19 PM, September 9 2014
txt = """Windmills are the greatest 
threat in the US to both bald 
and golden eagles. Media claims 
fictional ‘global warming’ is worse."""

ctext = encrypt(txt, encrypt_dict)
print(ctext + "\n")
print(encrypt(ctext, decrypt_dict))
XObLNOvvc eqB diB ZqBedBcd 
diqBed Ob diB IP dj Ejdi EevL 
ebL ZjvLBb BeZvBc. zBLOe oveONc 
VOodOjbev ‘ZvjEev neqNObZ’ Oc njqcB.

Windmills are the greatest 
threat in the US to both bald 
and golden eagles. Media claims 
fictional ‘global warming’ is worse.

Lösung zu Übung 4

latin2morse_dict = {'A':'.-', 'B':'-...', 'C':'-.-.', 'D':'-..', 
                    'E':'.', 'F':'..-.', 'G':'--.','H':'....', 
                    'I':'..', 'J':'.---', 'K':'-.-', 'L':'.-..', 
                    'M':'--', 'N':'-.', 'O':'---', 'P':'.--.', 
                    'Q':'--.-', 'R':'.-.', 'S':'...', 'T':'-', 
                    'U':'..-', 'V':'...-', 'W':'.--', 'X':'-..-', 
                    'Y':'-.--', 'Z':'--..', '1':'.----', '2':'...--', 
                    '3':'...--', '4':'....-', '5':'.....', '6':'-....', 
                    '7':'--...', '8':'---..', '9':'----.', '0':'-----', 
                    ',':'--..--', '.':'.-.-.-', '?':'..--..', ';':'-.-.-', 
                    ':':'---...', '/':'-..-.', '-':'-....-', '\'':'.----.', 
                    '(':'-.--.-', ')':'-.--.-', '[':'-.--.-', ']':'-.--.-', 
                    '{':'-.--.-', '}':'-.--.-', '_':'..--.-'}

# reversing the dictionary:
morse2latin_dict = dict(zip(latin2morse_dict.values(),
                            latin2morse_dict.keys()))

print(morse2latin_dict)
{'.-': 'A', '-...': 'B', '-.-.': 'C', '-..': 'D', '.': 'E', '..-.': 'F', '--.': 'G', '....': 'H', '..': 'I', '.---': 'J', '-.-': 'K', '.-..': 'L', '--': 'M', '-.': 'N', '---': 'O', '.--.': 'P', '--.-': 'Q', '.-.': 'R', '...': 'S', '-': 'T', '..-': 'U', '...-': 'V', '.--': 'W', '-..-': 'X', '-.--': 'Y', '--..': 'Z', '.----': '1', '...--': '3', '....-': '4', '.....': '5', '-....': '6', '--...': '7', '---..': '8', '----.': '9', '-----': '0', '--..--': ',', '.-.-.-': '.', '..--..': '?', '-.-.-': ';', '---...': ':', '-..-.': '/', '-....-': '-', '.----.': "'", '-.--.-': '}', '..--.-': '_'}
def txt2morse(txt, alphabet):
    morse_code = ""
    for char in txt.upper():
        if char == " ":
            morse_code += "   "
        else:
            morse_code += alphabet[char] + " "
    return morse_code

def morse2txt(txt, alphabet):
    res = ""
    mwords = txt.split("   ")
    for mword in mwords:
        for mchar in mword.split():
            res += alphabet[mchar]
        res += " "
    return res

mstring = txt2morse("So was?", latin2morse_dict)
print(mstring)
print(morse2txt(mstring, morse2latin_dict))
... ---    .-- .- ... ..--.. 
SO WAS? 

Lösung zu Übung 5

def heron(a, eps=0.000000001):
    """ Approximate the square root of a"""
    previous = 0
    new = 1
    while abs(new - previous) > eps:
        previous = new
        new = (previous + a/previous) / 2
    return new

print(heron(2))
print(heron(2, 0.001))
1.414213562373095
1.4142135623746899

Lösung zu Übung 6

def findnth(s, sub, n):
    num = 0
    start = -1
    while num < n:
        start = s.find(sub, start+1)
        if start == -1: 
            break
        num += 1
    
    return start

s = "abc xyz abc jkjkjk abc lkjkjlkj abc jlj"
print(findnth(s,"abc", 3))
19