Wahrscheinlich in einer Nishiki-Schlange (Originaltitel: Vielleicht in Python)

(Es ist kein übersetzter Artikel) Nein.

Vielleicht ist es gut, nicht wahr? Es macht es sehr einfach, mit dem Zustand eines Wertes und dem Zustand ohne Wert umzugehen. Es ist der Höhepunkt der von Lirin geschaffenen Kultur.

Also dachte ich, ich könnte etwas Ähnliches mit Python machen und implementierte es.

Der Hauptteil ist [hier] aufgeführt (https://gist.github.com/BlueRayi/fb999947e8f2a8037e7eea7ff9320f90). Ich denke, du solltest auf jeden Fall Masakari spielen und werfen.

Spezifikation

Einige von ihnen sind sich ausdrücklich bewusst, dass "null unsichere Sprachen keine Legacy-Sprachen mehr sind". Lesen Sie sie daher bitte zusammen. Ich denke es ist gut.

Basic

Dieses Vielleicht wird als konkrete Klassen "Etwas" und "Nichts" implementiert, die von der abstrakten Klasse "Vielleicht" erben. "Etwas" zeigt an, dass ein Wert vorhanden ist, und "Nichts" zeigt an, dass der Wert fehlt.

Die Funktion "nur" erstellt eine Instanz von "etwas". "nichts" ist die (einzige) Instanz von "nichts".

from maybe import just, nothing

a = just(42)
b = nothing

print(a)
print(b)
Just 42
Nothing

Vielleicht hat die Eigenschaft "has_value", "Something" gibt "True" zurück und "Nothing" gibt "False" zurück. Auch "Etwas" ist selbst Wahrheit und "Nichts" ist selbst Falsey.

print(a.has_value)
print(b.has_value)

print('-----')

if a:
    print('a is Truthy')
else:
    print('a is Falsy')

if b:
    print('b is Truthy')
else:
    print('b is Falsy')
True
False
-----
a is Truthy
b is Falsy

Vielleicht kann man sich eine Box vorstellen, in die man Werte einfügen kann. Vielleicht kann selbst ein Wert sein, also kann vielleicht verschachtelt werden. Vielleicht hat das Konzept der "Tiefe". Die Tiefe des bloßen Werts beträgt 0. Die Tiefe von "Nichts" ist 1. Die Tiefe von "Etwas" ist "Inhaltstiefe + 1". Die Tiefe kann erhalten werden, indem sie an die Funktion "dep" übergeben wird.

from maybe import dep

a2 = just(a)
b2 = just(b)
print(a2)
print(b2)

print('-----')

print(dep(42))
print(dep(a))
print(dep(b))
print(dep(a2))
print(dep(b2))
Just Just 42
Just Nothing
-----
0
1
1
2
2

Vielleicht können gleiche Werte verglichen werden. "Etwas" wird als gleich angenommen, wenn sie "Etwas" sind und ihr Inhalt gleich ist. Wenn es sich um eine verschachtelte Struktur handelt, wird sie während der Rekursion ausgegraben. "Nichts" wird als gleich angenommen, wenn sie "Nichts" sind.

print(a == 42)
print(a == just(42))
print(a == a2)
print(a == b)
print(b == nothing)
print(b == b2)
print(b2 == just(nothing))
False
True
False
False
True
False
True

Möglicherweise verbindlich (mit Null-Check besetzt)

Um "Vielleicht [T]" als "T" zu verwenden,

  1. Stellen Sie sicher, dass Vielleicht einen Wert hat,
  2. Sie müssen "Vielleicht [T]" in "T" konvertieren.

Es ist möglich, es wie folgt zu verwenden, indem die if-Anweisung und der später beschriebene erzwungene Entpackungsoperator verwendet werden.

m = just(913)
if m.has_value:
    print(m.i + 555)
1488

Wenn diese beiden Prozesse jedoch getrennt werden, können die folgenden unerwarteten Ereignisse auftreten.

m = just(913)
if m.has_value:
    print(m + 555) #Vergessen Sie vielleicht das Auspacken[int]Und int kann nicht hinzugefügt werden
TypeError: unsupported operand type(s) for +: 'Something' and 'int'
m = nothing
print(m.i + 555) #Vergiss die Nullprüfung, wenn m Nichts ist, die schleimige Fliege
maybe.NullpoError: it GOT no value.

Vielleicht kann Vielleicht iteriert werden, "Etwas" generiert den Wert des Inhalts nur einmal, und "Nichts" generiert nichts und löst eine "StopIteration ()" - Ausnahme aus. Auf diese Weise können Sie die for-Anweisung verwenden, um eine Nullprüfung durchzuführen und gleichzeitig wie unten gezeigt umzuwandeln.

m = just(913)
for v in m:
    print(v + 555) #Dies wird nur ausgeführt, wenn m etwas ist
1468

Ich nenne dies die "Vielleicht-Bindung", weil es sich genauso anfühlt wie die Swift Optional-Bindung. Der Unterschied zur optionalen Bindung besteht darin, dass keine Abschattung (unter Verwendung des gleichen Variablennamens im Block) möglich ist und die Verzweigung zwischen fehlenden Werten etwas kompliziert ist.

Schauen wir sie uns der Reihe nach an. Wenn Sie aufgrund des variablen Bereichs von Python so etwas wie Shadowing ausführen, ändert sich "m" in der Kommentarzeile von "Vielleicht [int]" zu "int".

m = just(913)
print(m) #Hier vielleicht[int]
for m in m:
    print(m + 555)
print(m) #Hier int
Just 913
1468
913

Denken Sie, dass dies bequemer ist, weil Sie bereits Null aktiviert haben? Aber es ist eine Falle. Wenn der Wert von "m" fehlt, bleibt er "Vielleicht [int]". Sie dürfen sich von nun an nicht mehr mit "m" im selben Kontext wie "Vielleicht" befassen. Sie müssen Ihre Zeit damit verbringen, Angst vor der Möglichkeit zu haben, dass "m", das wie "int" aussieht, "nichts" ist. Ich weiß nicht, wofür Vielleicht ist. Ist es nicht viel anders als nur "Keine" zu verwenden (in der Tat ist es problematischer)?

Der nächste Unterschied. Möglicherweise möchten Sie den Prozess mit und ohne Wert verzweigen, anstatt ihn nur dann auszuführen, wenn ein Wert vorhanden ist. In Swift Optional können Sie wie folgt schreiben.

let m: Int? = nil
if let v = m {
    print(v + 555)
} else {
    print("Vielleicht hasst du mich?")
}

Die Entsprechung zwischen "wenn" und "sonst" ist schön und konkurrenzlos. Und diese beiden Blöcke sind grammatikalisch gepaart.

In Vielleicht müssen wir jedoch so schreiben.

m = nothing
for v in m:
    print(v + 555)
if not m.has_value:
    print("Vielleicht hasst du mich?")

Die Korrespondenz zwischen "für" und "wenn" wurde wahrscheinlich geboren und niemand hat sie jemals gesehen. Außerdem sind diese beiden Blöcke nebeneinander geschrieben und kein grammatikalisches Paar. Außerdem ist "wenn nicht m.has_value" ziemlich lang. In Bezug darauf ist "Nichts" ursprünglich Falsey, also "wenn nicht" ist in Ordnung, aber es gibt einen Nachteil, dass die Bedeutung des Textes etwas schwer zu lesen ist.

Das heißt, es ist viel sicherer und einfacher zu schreiben, als wenn der Null-Check und die Besetzung getrennt sind. Grundsätzlich ist es besser, die Verwendung von ".i" zu verbieten und die Vielleicht-Bindung zu verwenden.

Erzwungener Entpackungsoperator (von !, !!)

Stellen Sie sich eine Funktion safe_int vor, die versucht, von str nach int zu konvertieren, und bei einem Fehlschlag nothing zurückgibt.

def safe_int(s):
    try:
        return just(int(s))
    except ValueError:
        return nothing

Angenommen, diese Funktion enthält eine Zeichenfolge, die aus dem Textfeld "Alter" springt, das auf einer bestimmten Site verwendet wird. Normalerweise dürfen Sie nur Zahlen auf der HTML-Seite eingeben, und die Vorverarbeitung erfolgt in der vorherigen Phase mit JavaScript.

In solchen Fällen ist es für diese Funktion praktisch unmöglich, "nichts" zurückzugeben. Trotzdem kann "Vielleicht [int]" nicht als "int" verwendet werden. Muss ich also lange Zeit eine Vielleicht-Bindung schreiben? Dann ist es besser, "Keine" zu verwenden.

Dann sollten Sie den erzwungenen Entpackungsoperator ".i" verwenden. Übrigens, obwohl es als Operator bezeichnet wird, ist es tatsächlich eine Eigenschaft.

s = get_textbox('Alter')
age = safe_int(s).i # .Ich weise dem Alter eine ganze Zahl zu
if age >= 20:
    ...

Es scheint bequem und problemlos zu sein, aber wenn Sie ".i" für "nichts" nennen, wird der gute alte den ursprünglichen "NullpoError" fliegen. Auch hier wird der erzwungene Entpackungsoperator als "unsichere" Operation betrachtet und sollte nur verwendet werden, wenn er in der Logik niemals "nichts" sein kann.

Null bedingter Operator (von ? .,? -> )

Angenommen, Sie haben hier eine "Vielleicht [Liste]". Sie wollten herausfinden, wie viele Nullen darin enthalten sind. Ich denke, vielleicht könnte "nichts" sein, aber die meiste Zeit, wenn die Liste selbst nicht existiert, würde man "nichts" erwarten (nein, einige Leute wollen "0"). Siehe auch den folgenden „Null-Heilungsoperator“.

Um ehrlich zu sein, sieht es so aus:

l = get_foobar_list('hogehoge')

for l0 in l:
    num_0 = just(l0.count(0))
if not l:
    num_0 = nothing

Ich kann es sicher schreiben, aber um klar zu sein, es ist kompliziert. Wenn l`` list ist, möchten Sie den Prozess, dernum_0 = l.count (0)erfordert, nicht über 4 Zeilen schreiben.

Sie können es mit dem Null-Bedingungsoperator .q. präzise schreiben (wie üblich ist es wirklich eine Eigenschaft).

l = get_foobar_list('hogehoge')
num_0 = l.q.count(0)

Sie können .q [] auch für Indizes verwenden.

l = get_foobar_list('hogehoge')
print(l.q[3])

#Kann anstelle von verwendet werden
# for l0 in l:
#     print(just(l0[3]))
# if not l:
#     print(nothing)

Warum können wir das tun? .Q gibt ein Objekt zurück, das von der abstrakten Klasse SafeNavigationOperator erbt. SafeNavigationOperator überschreibt __getattr__ und __getitem__. Wenn es einen Wert hat, wird "Something SNO" zurückgegeben. Dies enthält die Wertinformationen und __getattr__ und __getitem__ wickeln sie in just ein und geben sie zurück. Wenn der Wert fehlt, wird "NothingSNO" zurückgegeben, und "getattr" und "getitem" geben einfach "nichts" zurück.

Sie fragen sich vielleicht, ob Sie hier eine gute Idee haben. some_list.count ist eine Methode und ein aufrufbares Objekt. Maybe_list.q.count wird zurückgegeben, indem die Funktion in Vielleicht weiter eingeschlossen wird. Ist es ein aufrufbares Objekt von Vielleicht selbst, dass es wie "l.q.count (0)" behandelt werden kann?

In der Tat ist das richtig. Wenn Sie "Something" aufrufen, wird der Inhalt aufgerufen und das Ergebnis in "just" eingeschlossen und zurückgegeben. Das Aufrufen von "Nichts" gibt einfach "Nichts" zurück. Diese Spezifikation ermöglicht es, die oben genannten Dinge zu tun. Diese Spezifikation ist gleichzeitig mit ".q." zu verwenden. Ich persönlich halte es für magisch, es auf andere Weise zu verwenden, daher halte ich es für besser, es nicht zu verwenden (dies führt zu dem Grund, warum die vier Regeln von Vielleicht, die später beschrieben werden, nicht implementiert werden).

Übrigens, selbst unter den Sprachen, die "?" Implementieren, endet die sogenannte "optionale Kette", wenn Null gefunden wird (sozusagen Kurzschlussauswertung), aber ".q." Im Fall von wird der Prozess mit "nichts" fortgesetzt. Selbst wenn Sie ".q." für "nichts" tun, erhalten Sie nur "nichts", und das Ergebnis der Weitergabe entspricht immer noch Null, aber Sie sollten sich dieses Unterschieds bewusst sein. Möglicherweise müssen Sie es behalten.

Übrigens können Sie so etwas wie foo.q.bar = baz nicht machen, weil Sie __setattr__ nicht überschrieben haben. Dies ist meine technische Einschränkung und ich konnte die Endlosschleife, die beim Überschreiben von __setattr__ auftritt, einfach nicht lösen. Bitte hilf mir ... Ich denke, dass foo.q [bar] = baz gemacht werden kann, aber es ist bisher nicht implementiert, weil die Symmetrie gebrochen ist.

Nullfusionsoperator (von ?:, ??)

Im Fall von Null ist das Ausfüllen mit dem Standardwert wahrscheinlich die häufigste Anforderung beim Umgang mit Null.

Natürlich kann man auch mit Vielleicht verbindlich schreiben, aber ...

l = get_foobar_list('hogehoge')
num_0 = l.q.count(0) #Übrigens, hier ist num_0 ist vielleicht[int]damit……

for v in num_0:
    num_0 = v
if not num_0:
    num_0 = 0

#Wenn Sie hier rauskommen, num_0 wird int.

Der Null-Fusionsoperator [^ coalesce] >> ist ordnungsgemäß vorbereitet.

l = get_foobar_list('hogehoge')
num_0 = l.q.count(0) >> 0 # num_0 ist int

Das Verhalten des Null-Fusionsoperators sieht auf den ersten Blick einfach aus (und ist eigentlich einfach), erfordert jedoch ein wenig Aufmerksamkeit.

Wenn der Wert auf der linken Seite fehlt, ist die Geschichte einfach und die rechte Seite wird so zurückgegeben, wie sie ist.

Wenn andererseits die linke Seite einen Wert hat, verhält sie sich interessant (im translatorischen Sinne von Interessant). Wenn die linke Seite tiefer als die rechte Seite ist, werden der Inhalt der linken und der rechten Seite wieder vereint. Wenn die rechte Seite tiefer als die linke Seite ist, wickeln Sie die linke Seite mit "nur" ein und heilen Sie dann erneut. Wenn sie gleich sind, wird die linke Seite zurückgegeben. Wenn die rechte Seite jedoch ein bloßer Wert ist (Tiefe 0), wickeln Sie die rechte Seite in "just" ein und vereinheitlichen Sie den Inhalt erneut und geben Sie ihn zurück.

Der Operator "oder", der sich von außen ähnlich verhält, ist viel komplizierter als die Rückgabe, wenn die linke Seite "Wahrheit" ist. Der Grund dafür ist, dass aufgrund eines rekursiven Aufrufs immer ein Wert mit der gleichen Tiefe wie auf der rechten Seite zurückgegeben wird.

Im Zusammenhang mit dem Festlegen eines Standardwerts würden Sie erwarten, dass dieser mit oder ohne Wert gleich behandelt wird. Möglicherweise kann verschachtelt werden, so dass einige umständliche Operationen erforderlich sind. Dies ist jedoch eine interne Geschichte, und der Benutzer kann sie einfach als „immer einen Wert mit derselben Struktur zurückgeben“ behandeln.

Wenn es beispielsweise mehrere Vielleicht gibt, können Sie unabhängig von ihrer Struktur wie folgt "Vielleicht mit derselben Struktur wie die Seite ganz rechts (in diesem Fall bloßer Wert), wo der Wert am frühesten erscheint" erhalten. Ich werde.

x = foo >> bar >> baz >> qux >> 999

Beachten Sie jedoch, dass die rechte Seite ausgewertet wird, da es sich nicht um eine Kurzschlussbewertung handelt.

Dieser Operator wird übrigens durch Überladen des richtigen Bitverschiebungsoperators implementiert. Daher ist auch die Berechnungspriorität gleich. Das heißt, es ist niedriger als der Additionsoperator und höher als der Vergleichsoperator [^ Operator-Priorität]. Dies liegt nahe an der Priorität des Null-Fusionsoperators von C # [^ c-scharf], Swift [^ swift], Kotlin [^ kotlin], aber andererseits des in PEP 505 vorgeschlagenen "nicht-bewussten Operators". Dies unterscheidet sich sehr von [^ pep-505], wo ?? eine höhere Priorität hat als die meisten binären Operatoren. Bitte seien Sie vorsichtig, wenn der Tag, an dem PEP 505 offiziell verabschiedet wird (ich glaube nicht, dass es kommen wird). Außerdem wird >> =` automatisch definiert.

a = just(42)
b = nothing

print(a >> 0 + 12) # 42 ?? 0 +12 wäre 54(Haz)

print('-----')

a >>= 999
b >>= 999

print(a)
print(b)
42
-----
42
999

Nebenbei habe ich ">>" als Überlastungsziel gewählt.

  1. Einige Leute schreiben so, dass sich das handgeschriebene „?“ Vom „>“ nach unten erstreckt und einen Punkt (ähnlich in der Form) bildet.
  2. Auf der Tastatur stehen "?" Und ">" nebeneinander (ähnlich wie bei der Eingabe).
  3. Wenn Sie mehrere Elemente nebeneinander schreiben, ist es visuell leicht zu verstehen, dass die Werte in der Reihenfolge von links überprüft werden (Visualisierung der Verarbeitungslogik).
  4. Nahe an der Priorität des Null-Fusionsoperators in anderen Sprachen (weniger verwirrend)

Und so weiter. ~~ Es scheint, dass je niedriger Sie gehen, desto rationaler der Grund, aber das Beängstigende ist, dass je niedriger Sie gehen, desto mehr der Grund für die Nachrüstung ist und Sie sehen können, dass der Autor Vielleicht angemessen gemacht hat. ~~

[^ Koaleszenz]: Im Allgemeinen lautet die Standardübersetzung des Null-Koaleszenz-Operators "Null-Koaleszenz-Operator", aber "Koaleszenz" fehlt die Nuance "Ausfüllen des fehlenden Teils", was "Wunde schließen" bedeutet. "Heilung" wird verwendet.

map Methode (von map)

Der Null-Bedingungsoperator hat tatsächlich seine Schwächen. Es kann nur mit Vielleicht-Objekten verwendet werden. Sie können "SafeNavigationOperator" auch nicht als Argument angeben.

Das bedeutet, dass Sie dies nicht tun können.

l = just([1, 2, 3, ])

s = .q.sum(l) #Syntax-Fehler
s = sum(l.q) #Ausnahme zum Pop

#Warum machst du das nicht?
#Oah, oh, oh, oh, oh, ♥

Sie können mit Vielleicht Bindung schreiben, aber es ist immer noch kompliziert.

l = just([1, 2, 3, ])

for l0 in l:
    s = just(sum(l0))
if not l:
    s = nothing

Es gibt eine "Map" -Methode, um dies von der Objektseite "Vielleicht" aus zu tun. Mit der map Methode können Sie schreiben:

l = just([1, 2, 3, ])

s = l.map(sum)

Die an die map -Methode übergebene Funktion gibt das in just eingeschlossene Ergebnis zurück. Wenn der Wert fehlt, wird natürlich "nichts" zurückgegeben. Sie können auch Lambda-Ausdrücke für Funktionen verwenden, um Folgendes zu tun:

a = just(42)
print(a.map(lambda x: x / 2))
Just 21.0

Über die "Map" -Methode gibt es nicht viel zu sagen (besonders wenn Sie Monad kennen).

bind Methode (von flatMap)

Erinnern Sie sich an die zuvor erstellte Funktion "safe_int". Es nimmt "str" als Argument und gibt "Vielleicht [int]" zurück. Wenden wir dies mit map aufVielleicht [str]an.

s1 = just('12')
s2 = just('hogehoge')
s3 = nothing

print(s1.map(safe_int))
print(s2.map(safe_int))
print(s3.map(safe_int))
Just Just 12
Just Nothing
Nothing

safe_int gibt Vielleicht zurück, und die map -Methode umschließt es mit just, sodass es verschachtelt ist. Vielleicht wollte die Person, die dieses Programm geschrieben hat, dieses Ende nicht (die Tatsache, dass "verschachtelt werden kann", macht es aussagekräftiger. Wenn das Ergebnis der JSON-Analyse beispielsweise "null" enthält, dann "nur" (nichts) , denn wenn der Schlüssel überhaupt nicht existiert hätte, könnte er als nichts` ausgedrückt werden).

Bisher wurde es geheim gehalten, aber Sie können die Join-Funktion verwenden, um die Nester in einem Schritt zu zerstören. Es ist eine natürliche Umwandlung μ.

from maybe import join

print(join(s1.map(safe_int)))
print(join(s2.map(safe_int)))
print(join(s3.map(safe_int)))
Just 12
Nothing
Nothing

Und vor allem ist es wünschenswert, "map" und "join" zu kombinieren. Wenn Sie eine Bindemethode haben, können Sie diese verwenden.

print(s1.bind(safe_int))
print(s2.bind(safe_int))
print(s3.bind(safe_int))
Just 12
Nothing
Nothing

Für diejenigen, die die Haskell ~~ Transformation ~~ beherrschen, können Sie leicht verstehen, dass die map Methode der <$> Operator und die bind Methode der >> = Operator ist. Denken Sie daran, "map" für Funktionen, die nackte Werte zurückgeben, und "bind" für Funktionen, die "Maybe" zurückgeben.

do Funktion (von do Notation)

Natürlich werden map und bind von einem Maybe-Objekt aufgerufen, daher ist es etwas schwierig, sie für Funktionen zu verwenden, die zwei oder mehr Argumente annehmen.

lhs = just(6)
rhs = just(9)

ans = lhs.bind(lambda x: rhs.map(lambda y: x * y))
print(ans)
Just 54

Das Innere ist übrigens "map", weil es eine Funktion ist, die einen bloßen Wert mit "x * y" zurückgibt, und das Äußere ist "bind", weil der Rückgabewert der "map" -Methode "Maybe" ist. Erinnerst du dich?

Sie können dies einfach mit der Funktion "do" schreiben.

from maybe import just, nothing, do

lhs = just(6)
rhs = just(9)

ans = do(lhs, rhs)(lambda x, y: x * y)
print(ans)
Just 54

Die Funktion "do" extrahiert den Inhalt und führt die Funktion nur aus, wenn alle Argumente Werte haben. Gibt "nichts" zurück, wenn ein Wert fehlt. Der Name "do" stammt von Haskell, aber der Algorithmus ist extrem anti-monadisch. Vergib mir.

Das Argument der Funktion "do" kann übrigens nur von Maybe übernommen werden. Wenn Sie bloße Werte als Argumente verwenden möchten, schließen Sie sie in "nur" ein.

Andere Dinge

Vielleicht als Container

Vielleicht ist auch ein Container, und Sie können die Operatoren "len" und "in" verwenden.

Die len Funktion gibt immer 1 für Something und 0 für Nothing zurück.

a = just(42)
b = nothing
a2 = just(a)
b2 = just(b)

print(len(a))
print(len(b))
print(len(a2))
print(len(b2))
1
0
1
1

Der Operator "in" gibt "True" zurück, wenn der Inhalt der rechten Seite gleich der linken Seite ist. Andernfalls wird "False" zurückgegeben. Nothing gibt immer False zurück.

print(42 in a)
print(42 in b)
print(42 in a2)
print(42 in b2)
True
False
False
False

Wie bereits erwähnt, kann Vielleicht iterativ sein. So können Sie es beispielsweise in eine Liste konvertieren. @koher sagte: Genau das ist das Ergebnis.

Optional war eine Box, die möglicherweise leer ist. Unter einem anderen Gesichtspunkt können Sie sich "Optional" als "Array" vorstellen, das höchstens ein Element enthalten kann.

al = list(a)
bl = list(b)

print(al)
print(bl)
[42]
[]

Es ist ein Rätsel, ob es hier die Möglichkeit gibt, die Spezifikationen zu verwenden.

Verbinde dich mit der einheimischen Welt

Vielleicht hat ein Paar Funktionen und Methoden, vielleicht_von und to_native. Es ist ein Paar von Funktionen und Methoden. Diese arbeiten, um die nativen Python-Typen mit Maybe zu verbinden.

Maybe_from nimmt einen nativen Wert und gibt Vielleicht zurück. Der Unterschied zu "nur" besteht darin, dass bei "Keine" "nichts" anstelle von "nur (keine)" zurückgegeben wird und wenn "Vielleicht" angegeben wird, es so zurückgegeben wird, wie es ist. Diese Funktion kann verwendet werden, um gemeinsam die Rückgabewerte vorhandener Funktionen und Methoden zu verwenden, die fehlende Rückgabewerte im allgemeinen Kontext von Vielleicht als "Keine" anzeigen.

#Bestehende Funktion, die None anstelle von price zurückgibt, wenn sie nicht im Wörterbuch enthalten ist
def get_price(d, name, num, tax_rate=0.1):
    if name in d:
        return -(-d[name] * num * (1 + tax_rate)) // 1
    else:
        return None

# ...

from maybe import maybe_from
p = get_price(unit_prices, 'apple', 5) #int kann kommen, niemand darf kommen
p = maybe_from(p) #p ist Einheit_zu Preisen'apple'Vielleicht mit oder ohne[int]

Die Methode "to_native" macht "Vielleicht" zu einem nativen Wert (obwohl es nur ein nativer Wert ist, wenn der Inhalt ein Objekt ist, das von einer Bibliothek bereitgestellt wird). Im Gegensatz zu ".i" gibt "nichts" "Keine" zurück (aber missbrauchen Sie es nicht als "sicheren" Unwrap-Operator), und selbst wenn es verschachtelt ist, gräbt es rekursiv und ist immer nackt. Gibt den Wert von zurück. map betrachtet das Ganze als fehlend, wenn das Argument fehlt, aber dies kann als Argument für eine Funktion verwendet werden, die erwartet, dass None keinen Wert bedeutet. Sie können es auch als JSON-Serialisierungsmethode angeben, indem Sie die Tatsache verwenden, dass es einen nativen Wert zurückgibt (obwohl es als nativ abgekürzt wird).

import json

from maybe import Maybe

def json_serial(obj):
    if isinstance(obj, Maybe):
        return obj.to_native()
    raise TypeError ("Type {type(obj)} not serializable".format(type(obj)))

item = {
    'a': just(42),
    'b': nothing
}

jsonstr = json.dumps(item, default=json_serial)
print(jsonstr)
{"a": 42, "b": null}

Unterschiede zu PyMaybe und Antworten auf "Ist es nicht nur ein Ärger?"

Wenn Sie Vielleicht in Python sagen, gibt es eine vorhandene Bibliothek namens "PyMaybe". Es scheint ein berühmter Ort zu sein, der in PEP 505 erwähnt wird.

Das große Merkmal hier ist, dass Sie damit umgehen können, als ob es ein bloßer Wert wäre. Insbesondere der folgende Code in README.rst ist hilfreich. Stellen Sie sich hier "vielleicht" als "vielleicht_von" und hier "or_else" als ">>" Operator vor.

>>> maybe('VALUE').lower()
'value'

>>> maybe(None).invalid().method().or_else('unknwon')
'unknwon'

Wir rufen eine Methode für bloße Werte für Werte auf, die in Vielleicht eingeschlossen sind. Sie können auch sehen, dass der Methodenaufruf für Null ignoriert und Null weitergegeben wird. Sie müssen es nicht herausnehmen oder .q. wie mein Vielleicht tun. Es scheint, dass auch Dunder-Methoden wie vier Regeln implementiert sind.

Warum ist das nicht bequemer? Ich denke, viele Leute denken, dass es keine zusätzlichen Fehler geben wird.

Es gibt jedoch einen Grund, warum ich Vielleicht mit einer solchen Spezifikation implementiert habe. Es geht nur darum, einen Fehler auszulösen.

Wenn Sie den Unterschied zwischen "Vielleicht [T]" und "T" nicht richtig erkennen, wird sofort eine Fehlermeldung angezeigt, die Ihnen hilft, den Unterschied zu erkennen. Wenn Sie es verwirren, erhalten Sie sofort eine Fehlermeldung. Wenn Sie es in einen String konvertieren, wird ihm ein zusätzliches "Just" vorangestellt. Es soll sichergestellt werden, dass "wenn Sie es nicht richtig schreiben, es nicht funktioniert". Wenn Sie einen Fehler machen, werden Sie ihn sofort bemerken (siehe: Wenn Sie es ernst meinen, haben Sie keine Angst vor dem optionalen Jahr (2018)). Dies ist auch der Grund, warum ich nicht möchte, dass Vielleicht direkt aufgerufen wird (weil es den Unterschied verbirgt, obwohl ich die Zeichenfolgenkonvertierung wirklich löschen möchte ...).

Es ist allgemein bekannt, dass die Nullsicherheit ein Mechanismus ist, der nicht schleimig ist, und es besteht kein Zweifel daran, dass der endgültige Zweck darin besteht (und plötzlich begann ich über die Nullsicherheit zu sprechen, aber meine Vielleicht sind die Typhinweise nutzlos, daher ist es praktisch unmöglich, sie für die Null-Sicherheit zu verwenden. Was jedoch für die Nullsicherheit wirklich notwendig ist, ist „eine Unterscheidung zwischen Nullable und Non-Null“. Warum ist Java nicht fehlgeschlagen? Sie konnten jedem Referenztyp "null" zuweisen, und umgekehrt konnte der Wert jedes Referenztyps "null" sein. Die Tatsache, dass "T" Null sein kann, bedeutet, dass Sie es nicht als "T" verwenden können, obwohl Sie "T" geschrieben haben. Sollte sein. Es ist ziemlich gefährlich, dorthin zu gelangen und die Barriere zwischen Nullable und Non-Null weiter zu durchbrechen - Dinge, die nicht "T" sind, wie "T" behandeln zu lassen - ist ziemlich gefährlich.

Objective-C hat eine schlechte Angabe, dass Methodenaufrufe an nil ohne Fehler ignoriert werden.

(Weggelassen)

Als Gegenleistung für diese Bequemlichkeit birgt Objective-C jedoch auch ein schreckliches Risiko. Ich habe vergessen, das "Null" zu überprüfen, wo ich das "Null" hätte überprüfen sollen, aber manchmal funktioniert es einfach. Und eines Tages, wenn sich bestimmte Bedingungen überschneiden oder eine kleine Korrektur vorgenommen wird, wird der Fehler offensichtlich.

Der Umgang von Objective-C mit Nullen scheint auf den ersten Blick sicher zu sein, verzögert nur die Entdeckung von Problemen und erschwert deren Lösung. Ich halte die Objective-C-Methode für die schlechteste, da sie für potenzielle Fehler anfällig ist. Es war einmal, als ich ein in Objective-C geschriebenes Programm nach Java portierte, erst als in Java eine NullPointerException auftrat, wurde mir klar, dass die Nullbehandlung auf der Objective-C-Seite unangemessen war. war.

Das bedeutet natürlich nicht, dass Sie für die Null-Sicherheit weniger produktiv sein müssen. Eine Nullprüfung für nullfähige Variablen war „auch in der alten Sprache“ erforderlich [^ null-check], und dies implementierte möglicherweise eher verschiedene Möglichkeiten, um dies zu vereinfachen. Wenn Sie es treffen möchten, ohne Null zu aktivieren, gibt es dafür sogar eine unsichere Operation. Dieser Bereich ist [eine Geschichte, die vor einigen Jahren erzählt wurde](https://qiita.com/koher/items/e4835bd429b88809ab33#null-%E5%AE%89%E5%85%A8%E3%81%AF%E7 % 94% 9F% E7% 94% A3% E6% 80% A7% E3% 82% 82% E9% AB% 98% E3% 82% 81% E3% 82% 8B).

Ich denke jedoch, dass diejenigen, die Python verwenden möchten, sich dieser Robustheit und des Wertes bewusst sind, "schreibe, was du ehrlich schreiben willst". Ich kann also nicht sagen, dass PyMaybes Idee falsch ist ~~ Ich kann sagen, dass ich der "Vielleicht [T] -Fehler" bin, der sich gegen die Welt auflehnt ~~. Bitte zögern Sie jedoch nicht zu sagen, dass Sie halb spielen oder dass Sie geschrieben haben, was Sie schreiben möchten.

[^ null-check]: Dies ist eine unrealistische Geschichte für ein personalisiertes Vielleicht, aber wenn [nur "nichts" und nicht das eingebaute "Keine" verwenden](https://twitter.com/ kmizu / status / 782360813340286977) Wenn Sie können (wickeln Sie es in Maybe_from ein, sobald es auftreten kann), müssen Sie keine Nullprüfung auf nackte Werte durchführen. Tatsächlich ist dies der größte Vorteil von Null-sicheren Sprachen, und Null-sichere Sprachen, deren Sprachspezifikationen einen solchen Mechanismus enthalten, müssen nur eine „notwendige Nullprüfung“ durchführen. Die allgemeine Auffassung, dass „Null-sichere Sprachen Nullprüfungen erzwingen“, ist richtig, aber das Gegenteil ist der Fall. Referenz: [Anti-Pattern] -Syndrom, das möglicherweise alle null (null) ist

Recommended Posts

Wahrscheinlich in einer Nishiki-Schlange (Originaltitel: Vielleicht in Python)
Machen Sie einen Screenshot in Python
Erstellen Sie eine Funktion in Python
Erstellen Sie ein Wörterbuch in Python
Erstellen Sie ein Lesezeichen in Python
Zeichne ein Herz in Python
Schreiben Sie eine Dichotomie in Python
[Python] Verwalten Sie Funktionen in einer Liste
Drücken Sie einen Befehl in Python (Windows)
Erstellen Sie einen DI-Container mit Python
Zeichnen Sie eine Streudiagrammmatrix mit Python
ABC166 in Python A ~ C Problem
Schreiben Sie A * (A-Stern) -Algorithmen in Python
Erstellen Sie eine Binärdatei in Python
Löse ABC036 A ~ C mit Python
Schreiben Sie ein Kreisdiagramm in Python
Schreiben Sie das Vim-Plugin in Python
Schreiben Sie eine Suche mit Tiefenpriorität in Python
Implementierung eines einfachen Algorithmus in Python 2
Implementierung der ursprünglichen Sortierung in Python
Löse ABC037 A ~ C mit Python
Führen Sie einen einfachen Algorithmus in Python aus
Zeichnen Sie ein CNN-Diagramm in Python
Erstellen Sie eine zufällige Zeichenfolge in Python
Beim Schreiben eines Programms in Python
Generieren Sie eine erstklassige Sammlung in Python
Spiralbuch in Python! Python mit einem Spiralbuch! (Kapitel 14 ~)
Löse ABC175 A, B, C mit Python
Verwenden Sie print in Python2 lambda expression
Ein einfacher HTTP-Client, der in Python implementiert ist
Führen Sie eine nicht rekursive Euler-Tour in Python durch
Ich habe ein Pay-Management-Programm in Python erstellt!
Vorsichtsmaßnahmen beim Beizen einer Funktion in Python
Schreiben Sie den Test in die Python-Dokumentzeichenfolge
Zeigen Sie eine Liste der Alphabete in Python 3 an
Versuchen Sie, ein SYN-Paket in Python zu senden
Versuchen Sie, eine einfache Animation in Python zu zeichnen
Erstellen Sie eine einfache GUI-App in Python
Schreiben Sie eine kurze Eigenschaftsdefinition in Python
Mit Python Teil 2 ein Herz zeichnen (SymPy Edition)
[Python] [Windows] Machen Sie eine Bildschirmaufnahme mit Python
Führen Sie den Python-Interpreter im Skript aus
Wie bekomme ich Stacktrace in Python?
Schreiben Sie ein Caesar-Verschlüsselungsprogramm in Python
Hash in Perl ist ein Wörterbuch in Python
Scraping von Websites mit JavaScript in Python
Schreiben Sie eine einfache Giermethode in Python
Starten Sie eine Flask-App in Python Anywhere
Holen Sie sich ein Zeichen für Conoha mit Python
Löse ABC165 A, B, D mit Python
[GPS] Erstellen Sie eine kml-Datei mit Python
Schreiben Sie ein einfaches Vim-Plugin in Python 3
Zeichnen Sie mit graphviz eine Baumstruktur in Python 3
Generieren Sie eine Klasse aus einer Zeichenfolge in Python
Pyopengl im Browser anzeigen (Python + Aal)
Lassen Sie uns eine Kombinationsberechnung mit Python durchführen
Probieren Sie eine funktionale Programmierpipe in Python aus