Funktionale Programmierung in Python (auf Englisch)

Gute Links und Tutorials könnt ihr hier posten.
Antworten
Benutzeravatar
paedubucher
User
Beiträge: 30
Registriert: Donnerstag 29. Juni 2006, 18:29
Wohnort: Schweiz
Kontaktdaten:

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
Benutzeravatar
__blackjack__
User
Beiträge: 13004
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:

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]
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.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

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."
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

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

Code: Alles auswählen

>>> numbers = range(1, 4)
>>> list(numbers)
[1, 2, 3]
>>> "__iter__" in dir(numbers)
True
Benutzeravatar
__blackjack__
User
Beiträge: 13004
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:

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
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.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@__blackjack__: ja stimmt, ich hatte lediglich auf __iter__() geachtet und übersehen das __next__() fehlt, was den Iterator ausmacht.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1012
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

__iter__ -> Iterable
__next__ -> Iterator
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
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!
Antworten