Option Type als Rückgabewert.

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Hallo, in funktionalen Programmiersprachen gibt es Enums, die auch zusätzlich einen Wert beinhalten können. Die werden dann zB als Datentyp für Rückgabewerte verwendet.

Je nach Sprache und Funktionsweise heißen die Option Type, Sum Type, Maybe usw.

Gibt es ein Äquivalent dazu in Python?
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Suchst du Enum?
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Nein, ein Äquivalent zu Sum Types gibt es in Python nicht. Es gibt zwar wie schon erwähnt Enums, die sind aber nur eine sehr primitive und eingeschränkte Form davon. Sowas wie ein Option oder Maybe lässt sich damit nicht repräsentieren und ohnehin hat man ja mit None quasi einen Null Pointer.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Es gibt das neue structural pattern matching. Das ist in gewisser Weise ein äquavilent.
narpfel
User
Beiträge: 645
Registriert: Freitag 20. Oktober 2017, 16:10

Man kann Sum Types durch (sealed) Klassen und Vererbung nachbauen, kleines Beispiel:

Code: Alles auswählen

from typing import Generic
from typing import Sequence
from typing import TypeVar

T = TypeVar("T")


class Maybe(Generic[T]):
    pass


class Just(Maybe[T]):
    __match_args__ = "_value",

    def __init__(self, value: T) -> None:
        self._value = value


class Nothing(Maybe[T]):
    __match_args__ = ()


def get(xs: Sequence[T], i: int) -> Maybe[T]:
    if i in range(len(xs)):
        return Just(xs[i])
    else:
        return Nothing()


def print_ith_value(xs: Sequence[T], i: int) -> None:
    match get(xs, i):
        case Just(value):
            print(f"index was present, {value = }")
        case Nothing():
            print("index was not present")


def main() -> None:
    xs = [1, 2, 3, 4]
    print_ith_value(xs, 2)
    print_ith_value(xs, 42)
    maybe_values = [Just(42), Nothing()]
    print_ith_value(maybe_values, 1)


if __name__ == "__main__":
    main()
Ausgabe:

Code: Alles auswählen

$ python t.py
index was present, value = 3
index was not present
index was present, value = <__main__.Nothing object at 0x7f79704db220>
In PEP 622 waren sealed classes noch vorhanden, aber in PEP 634 gibt es sie anscheinend nicht mehr. Dadurch verliert man dann halt das exhaustiveness checking; und `Maybe[T]` kann in Nutzer-Code als Basisklasse benutzt werden.
Benutzeravatar
__blackjack__
User
Beiträge: 13122
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Sieht irgendwie nicht wirklich nach Python aus.

Code: Alles auswählen

#!/usr/bin/env python3

NOTHING = object()


def get(xs, i):
    return xs[i] if 0 <= i < len(xs) else NOTHING


def print_ith_value(xs, i):
    value = get(xs, i)
    print(
        f"index was present, value = {value}"
        if value is not NOTHING
        else "index was not present"
    )


def main():
    xs = [1, 2, 3, 4]
    print_ith_value(xs, 2)
    print_ith_value(xs, 42)
    maybe_values = [42, None]
    print_ith_value(maybe_values, 1)


if __name__ == "__main__":
    main()
Beziehungsweise ohne einen speziellen Fehlerwert:

Code: Alles auswählen

#!/usr/bin/env python3


def print_ith_value(xs, i):
    try:
        value = xs[i]
    except IndexError:
        print("index was not present")
    else:
        print(f"index was present, value = {value}")


def main():
    xs = [1, 2, 3, 4]
    print_ith_value(xs, 2)
    print_ith_value(xs, 42)
    maybe_values = [42, None]
    print_ith_value(maybe_values, 1)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Das kommt allerdings erst in 3.10 und ich denke man kann dann auch überlegen ob man nicht eine simplere und einfachere Sprachen nimmt, früher oder später kommt da sicherlich auch Haskell oder Rust ganz unironisch in Frage, wenn Python weiter solche Features bekommt.

Kontext so siehts in Rust aus:

Code: Alles auswählen

fn print_ith_value<T: std::fmt::Debug>(xs: &[T], i: usize) {
    match xs.get(i) {
        Some(x) => println!("index was present, value = {:#?}", x),
        None => println!("index was not present")
    }
}

fn main() {
    let xs = vec![1, 2, 3, 4];
    print_ith_value(&xs, 2);
    print_ith_value(&xs, 42);
    let maybe_values = vec![Some(42), None];
    print_ith_value(&maybe_values, 1);
}

Rust Playground zum ausprobieren.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Wow, danke für die Antworten. Sieht leider alles nicht wirklich vielversprechend aus.

Tatsächlich überlege ich, zu Julia zu wechseln. Ich denke, dass ist ein adäquater Nachfolger für Python.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Benutzeravatar
__blackjack__
User
Beiträge: 13122
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@burli: Naja es gibt halt `None` und Ausnahmen in Python, warum sollte für den gleichen Zweck jetzt noch was anderes eingeführt werden?
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

burli hat geschrieben: Donnerstag 2. September 2021, 17:46 Ich denke, dass ist ein adäquater Nachfolger für Python.
Die Julia Community hätte es sicherlich sehr gerne das Julia ein Python Nachfolger wird. Tatsache ist aber das Julia inzwischen 9 Jahre alt ist und im Vergleich zu Rust (11 Jahre) oder Go (11 Jahre) es bisher nicht geschafft hat nennenswert an Beliebtheit zu gewinnen und ist bisher immer noch eine recht obskure ziemlich unbekannte Sprache. Das ist natürlich kein Wettrennen aber die Wahrscheinlichkeit dass es da nochmal mit der Popularität deutlich nach oben geht und Julia ernsthaft mit Python konkurriert ist wohl eher nicht so hoch.

Ich hab auch den Eindruck dass einige von Python zu Go gewechselt sind und davor von Python zu Javascript als node.js aufkam. Trotzdem würde ich sagen dass Python heute populärer ist als vor 5 oder 10 Jahren.

Man kann natürlich trotzdem Julia nutzen aber wenn man es nur tut weil es einige als Python Nachfolger sehen, wird man wahrscheinlich langfristig enttäuscht sein.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Hm, warum ist Julia "obskur"?
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na weil es eben wenig genutzt wird. Hat DasIch doch ausgeführt?
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Die Frage war eher, warum Julia so unbekannt ist. Ich hab zwar eine Vermutung, aber es würde mich trotzdem interessieren, warum Julia kaum verwendet wird.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sowas ist nicht schlüssig zu beantworten. Da kann jeder seine Lieblingsspekulation in den Ring werfen, und ewig drüber gestritten werden - ein Ergebnis wird’s nicht geben. Es gibt Sprachen mit hochgradig fragwürdigem Design, die trotzdem sehr erfolgreich sind. PHP und VB zb. Und andere wiederum sind auf dem Papier super, aber packen es nicht.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Ich denke hier gibt es schon ein paar Faktoren die ziemlich klar sind. Das fängt mit dem richtigen Zeitpunkt an, Python war durch numpy, scipy etc. schon zum Beginn des Data Science / Machine Learning Hypes sehr gut positioniert.

Ein weiterer Faktor ist das Python leicht zu lernen ist, zum einen weil die Sprache grundsätzlich leicht zu lernen ist, zum anderen weil es einfach viele Material dafür gibt. Bei uns im Unternehmen (Zalando) gibt es viele die Python (und R) nutzen obwohl sie nicht Software Entwickler oder Applied Scientists (Data Science, Machine Learning, Operational Research) sind sondern "nur" Analysten sind. Komplexe Features sind dementsprechend ein massiver Nachteil.

Am wichtigsten ist aber dass eine neue Sprache einen deutlichen Mehrwert bringen muss. PHP hat Webentwicklung trivial gemacht, Node.js vereint Frontend und Backend, Go macht es leicht Microservices zu implementieren, Rust macht Systemprogrammierung einfach (naja, einfacher als C oder C++ zumindest). Was macht Julia vergleichbares? Die Sprache ist etwas anders als Python und schneller aber der Kram der schnell sein muss ist ja ohnehin in C oder C++ implementiert. Julia mag in einigen Punkten besser sein aber nur irgendwie inkrementell besser sein recht nicht aus. Man muss durch das Lernen der Sprache etwas können (außer der Sprache selbst) was man vorher nicht konnte. Es muss da einen Quantensprung geben und den sehe ich nicht. Selbst wenn es den geben sollte, geht man auf https://julialang.org/ wird der nicht vermittelt.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Gegenrede (um meinen Punkt der Subjektivität darzustellen): Sowohl Lisp als auch Perl waren zum Zeitpunkt der Genesis von Python schon verfügbar. Mit in vielen Beziehungen (gerade zB CPAN) überlegenen Strukturen, für deren Nachbildung Python Jahre oder Jahrzehnte gebraucht hat. Einen solchen Quantensprung in Python vs dieser Sprachen sehe ich zB nicht, vor allem nicht zu den 1.5, 2.0-Zeiten, in denen Ich es zu meiner Lieblingssprache erkoren habe. Zu dem Zeitpunkt sprach ich Assembler, TCL, C++, VB und ein paar obskure Dinge. Trotzdem gefiel es mir einfach besser, ohne da einen konkreten Punkt ausfindig machen zu können.

Und genau das ist das Problem: Man kann diese Narrative liefern, und die sind ja auch schön eingängig. Sie sind aber, ebenso wie die Heldengeschichten um Steve Jobs & ApplezB, massiv von einem survivors bias geprägt. Wer sich auf die Suche macht, wird immer Dinge finden, die solche Thesen stützen.

Wäre zB Python gegenüber Julia ins Hintertreffen geraten - vielleicht zb einfach weil bei Google das entscheidende Team darauf gesetzt hat, weil der Manager es geil fand, aus so subjektiven Gründen wie damals ich Python - würden wir heute wahrscheinlich die ziemlich verkackte Python 3 Einführung als Grund ausfindig machen, warum’s bergab ging.

Darum halte ich solche Diskussionen für Spökenkiekern. Allen sachlichen Argumenten zum Trotz. Die deswegen ja trotzdem stimmen.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Julia hat einen Vorteil gegenüber Python, der von den Meisten aber vermutlich als Nachteil empfunden wird. Julia ist primär eine funktionale Sprache. Leider ist praktisch jede populäre Sprache Imperativ bzw objektorientiert.

Rust ist nur deshalb so erfolgreich, weil funktionale Konzepte in ein imperatives Korsett gezwängt werden. Die dabei entstehenden Probleme werden mit dem Borrow Checker abgefangen. Dadurch wirkt die Sprache noch halbwegs vertraut und die neuen Sprachfeatures kann man teilweise sogar umgehen.

Nicht falsch verstehen, ich bin ein Fan von Rust.

Aber ich gebe euch Recht. Die Gründe für das Schattendasein von Julia sind vermutlich vielfältig. Eventuell wird sie beliebter, wenn die funktionale Programmierung mindestens den gleichen Stellenwert in der Ausbildung hat wie die objektorientierte Programmierung.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Dominanz funktionaler Sprachen ist aehnlich weit weg wie die der Kernfusion. Schon seit 40 Jahren 15 Jahre in der Zukunft... siehe Lisp-Machines, etc.

Wenn es einen Vorteil von Python gibt, den es gegenueber anderen Sprachen auszeichnet, dann ist das ein geruettelt Mass Pragmatismus. Wir hatten mal einen Haskell-Vortrag in der Firma, mit der dazugehoerigen User-Gruppe. Alles sehr nette Leute, aber wenn man erstmal ein Studium der Kategorien-Theorie abgeschlossen haben muss, um sowas basales wie Datei- und Netzwerk-IO zu meistern, dann ist das ein bisschen viel verlangt.

Es ist auch nunmal so, dass wir in einem zunehmend vernetzten Computer-Universum mit funktionalen Sprachen nicht so besonders weit kommen. Denn die Realitaet sieht so aus, dass wir veraendrelichen Zustand (Objekte) und eine Vielzahl von kleinen, manipulierenden Operationen darauf haben. Nicht grosse, tief verzweigende Berechnungen auf einer Eingabe, die dann ein beeindruckendes Ergebnis liefern. Ein netter Vortrag den ich dazu neulich las hatte einen Titel in Richtung "Die unglueckliche Diktatur von return" oder sowas (in Englisch), bei der es genau um diesen Mismatch ging.

Und bevor der Verdacht aufkommt, ich haette ein Problem mit funktionalen Sprachen: meine Diplomarbeit hiess "Multi-Level-Spezifikation in funktionalen Sprachen" am Lehrstuhl fuer Uebersetzerbau und Programmiersprachen der TU Berlin. Kein Meisterwerk, aber ausreichend Exposition zu funktionalen Sprachen, Typkalkuelen etc hatte ich schon :)
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Es geht mir nicht um die Dominanz von funktionalen Sprachen. Haskell ist ein Extrembeispiel.

Aber ein funktionaler Programmier"Stil" hat schon seine Vorteile und da hilft es doch, wenn die Sprachen entsprechende Features wie eben Option Types und ähnliches hat.

Viele etablierte Sprachen wie Java pressen ja solche Features nachträglich rein, aber das sieht dann auch dementsprechend grausig aus und es macht nicht wirklich Spaß.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich finde Python hat schon immer funktionale Programmierung unterstuetzt. Denn Summentypen sind bei Python ja nun schlicht eingebaut dadurch, dass ich einfach jeden Typ benutzen kann. Ich kann None, 10, oder "tausend" zurueckgeben. Ein Summentyp aus None, int, str. Und ueber den Typen kann ich dann auch verzweigen.

Und noch praktischer sind Tupel, mit denen man vieles, was algebraische Typen machen, ja nun auch problemlos darstellen kann.

Ich mag die Rust'schen Enums (die ja nix anderes sind als algebraische Typen) auch gerne. Aber ich vermisse pattern-matching in Python nun wirklich nicht. Das ist ja nur eine Moeglichkeit als Kontrollstruktur. Und dank Garbage-Collection sind auch Exceptions kein solches Problem, wie sie das in Sprachen, die das nicht oder nur so wenig wie moeglich haben wollen, darstellen.

Und ich finde "pressen" schon sehr wertend. Multi-paradigmen-Sprachen erlauben einem, das zu benutzen, was man braucht, wann man es braucht. Monaden in funktionalen Sprachen sind schon ein unglaublicher Wuergaround um der simplen Tatsache, dass die Welt nicht abgeschlossen ist, konzeptionell einzufuehren. Da ist ein einfaches "file.read()" nun deutlich weniger gepresst...
Antworten