Hallo allerseits
Ich bin heute per Zufall auf dieses Forum gestolpert. Dabei fiel mir ein, dass ich vor über einem Jahrzehnt schon einmal hier aktiv gewesen bin. Damals habe ich hobbymässig Python gelernt. Zum Glück sind mir meine Zugangsdaten nach all den Jahren noch eingefallen, sodass ich meinen Account nach ca. 13 Jahren wieder reaktivieren konnte.
Mittlerweile arbeite ich hauptberuflich als Python-Entwickler. Ich habe diesen Sommer ein kleines Tutorial über die funktionale Programmierung in Python geschrieben, eigentlich eher eine Buchzusammenfassung mit eigenen Beispielen. Das ganze ist auf Englisch verfasst. Vielleicht hilft's ja jemandem.
Liebe Grüsse, und schön wieder mal hier zu sein...
paedubucher
Funktionale Programmierung in Python (auf Englisch)
- paedubucher
- User
- Beiträge: 30
- Registriert: Donnerstag 29. Juni 2006, 18:29
- Wohnort: Schweiz
- Kontaktdaten:
- __blackjack__
- User
- Beiträge: 13190
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Bei „Composing Functions“ finde ich es ein bisschen unfair einfach alle Funktionen rauszuwerfen und dann zu sagen weil man Funktionen nicht testen kann, ist es schwieriger Fehler zu finden. Denn auch beim prozeduralen Paradigma gibt es ja Prozeduren und Funktionen, die man dann auch (Unit-)Testen kann. Für das Beispiel sähe das dann eher so aus:
Bei der `Salary`-Klasse gefällt mir der Hack mit den Klassenvariablen als Defaultwerte nicht so wirklich. Und auch bei einer solchen Klasse könnte/würde man Default-Argumente in der `__init__()` erwarten. Die Beispiele sind auch asymmetrisch. `Salary` wird `amount` übergeben, aber `get_salary_func()` nicht‽ Welches Beispiel sollte da dem anderen angeglichen werden?
Diese „train wreck“-Methodenaufrufe sind auch nicht so wirklich ”pythonisch”, entsprechend selten findet man so etwas. Eine Methode die das Objekt verändert, gibt es in der Regel nicht als Rückgabwert, denn der Aufrufer hat das ja bereits, sonst hätte er die Methode nicht aufrufen können. Das ist in der Standardbibliothek ja eine bewusste Entscheidung gewesen, dass `list.append()` beispielsweise nicht die Liste zurück gibt.
Bei den externen Modulen würde ich `more_itertools` erwähnen. Das tut selbst die Python-Dokumentation für das `itertools`-Modul, weil in `more_itertools` unter anderem die ganzen ”Rezepte” aus der `itertools`-Dokumentation implementiert sind.
Code: Alles auswählen
def add_bonus(score, bonus):
return score + bonus
def grade_for(max_score, score):
return score / max_score * 5 + 1
def limit_of(max_grade, grade):
return min(grade, max_grade)
def round_to(granularity, value):
scaled_up = value * (1 / granularity)
rounded = round(scaled_up)
scaled_down = rounded * granularity
return scaled_down
def main():
max_score = 100
scores = [70, 80, 90, 40, 100]
bonus = max_score / 10
max_grade = 6.0
granularity = 0.1
grades = []
for score in scores:
score = add_bonus(score, bonus)
grade = grade_for(max_score, score)
grade = limit_of(max_grade, grade)
grade = round_to(granularity, grade)
grades.append(grade)
print(grades) # [5.0, 5.5, 6.0, 3.5, 6.0]
Diese „train wreck“-Methodenaufrufe sind auch nicht so wirklich ”pythonisch”, entsprechend selten findet man so etwas. Eine Methode die das Objekt verändert, gibt es in der Regel nicht als Rückgabwert, denn der Aufrufer hat das ja bereits, sonst hätte er die Methode nicht aufrufen können. Das ist in der Standardbibliothek ja eine bewusste Entscheidung gewesen, dass `list.append()` beispielsweise nicht die Liste zurück gibt.
Bei den externen Modulen würde ich `more_itertools` erwähnen. Das tut selbst die Python-Dokumentation für das `itertools`-Modul, weil in `more_itertools` unter anderem die ganzen ”Rezepte” aus der `itertools`-Dokumentation implementiert sind.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Viel Gutes finde ich. Dinge die ich verbessern wuerde:
- Das ist natuerlich Geschmackssache, aber das ganze sieht schon ein bisschen aus wie eine Todesanzeige. Ich faende eine der ueblichen Syntaxhighlighter fuer den Code gut.
- Bei der Gegenueberstellung Klassen zu Closures fehlt mir Einordnung, warum man wann welchen Stil bevorzugt. Also zB sowas wie "functional programming values immutability high, this can be conveniently achieved using closures. However if you need to retain state or want simpler introspection, classes are a better choice."
- Das ist natuerlich Geschmackssache, aber das ganze sieht schon ein bisschen aus wie eine Todesanzeige. Ich faende eine der ueblichen Syntaxhighlighter fuer den Code gut.
- Bei der Gegenueberstellung Klassen zu Closures fehlt mir Einordnung, warum man wann welchen Stil bevorzugt. Also zB sowas wie "functional programming values immutability high, this can be conveniently achieved using closures. However if you need to retain state or want simpler introspection, classes are a better choice."
Eine schöne Zusammenstellung.
Als konstruktive Anmerkung: Im Kapitel "Realizing Iterators" ist es nicht erforderlich iter() aufzurufen, da das von range() erzeugte objekt bereits ein Iterator ist
Als konstruktive Anmerkung: Im Kapitel "Realizing Iterators" ist es nicht erforderlich iter() aufzurufen, da das von range() erzeugte objekt bereits ein Iterator ist
Code: Alles auswählen
>>> numbers = range(1, 4)
>>> list(numbers)
[1, 2, 3]
>>> "__iter__" in dir(numbers)
True
- __blackjack__
- User
- Beiträge: 13190
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@kbr: Es stimmt das der Aufruf nicht nötig ist, aber nicht weil `range`-Objekte Iteratoren wären, das sind sie nämlich nicht:
Die sind iterierbar, aber keine Iteratoren. `list()` erwartet keinen Iterator, sondern ein iterierbares Objekt, also eines von dem man einen Iterator mit `iter()` bekommen kann. Und deswegen ist das `iter()` überflüssig, weil `list()` das intern selber schon macht.
Code: Alles auswählen
In [140]: next(range(42))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-140-1596066d6b4e> in <module>
----> 1 next(range(42))
TypeError: 'range' object is not an iterator
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
- paedubucher
- User
- Beiträge: 30
- Registriert: Donnerstag 29. Juni 2006, 18:29
- Wohnort: Schweiz
- Kontaktdaten:
Ich bedanke mich nachträglich für die zahlreichen und qualifizierten Rückmeldungen zu meinem Tutorial! Leider hat die Darstellung beim Generieren der HTML-Seite aus dem Markdown etwas gelitten (u.a. fehlende Tabelledarstellung), weswegen ich auf die Originaldatei verweisen möchte.
Von der Webseite werde ich dieses Tutorial wohl entfernen und es auf GitHub belassen, da es so unstrukturiert schlicht zu lange ist.
Bei Gelegenheit werde ich mich auch ausführlich den zahlreichen Rückmeldungen widmen und versuchen, die Beispiele zu verbessern. (Evtl. finde ich gegen Ende des Jahres noch etwas Zeit.)
Aber Danke soweit!
Von der Webseite werde ich dieses Tutorial wohl entfernen und es auf GitHub belassen, da es so unstrukturiert schlicht zu lange ist.
Bei Gelegenheit werde ich mich auch ausführlich den zahlreichen Rückmeldungen widmen und versuchen, die Beispiele zu verbessern. (Evtl. finde ich gegen Ende des Jahres noch etwas Zeit.)
Aber Danke soweit!