J'aime beaucoup utiliser les monades Option et SOUND à Scala. Y at-il un équivalent pour ces choses en Python? Si ce n’est pas le cas, quelle est la méthode pythonique de gestion des erreurs ou "absence de valeur" sans exception?
Eh bien, vraiment, pour Pythonic, une fonction qui dit "je ne suis pas défini à ce stade" consiste à lever une exception.
>>> int("blarg")
Traceback (most recent call last):
...
ValueError: invalid literal for int() with base 10: 'blarg'
>>> dict(foo=5)['bar']
Traceback (most recent call last):
...
KeyError: 'bar'
>>> 1 / 0
Traceback (most recent call last):
...
ZeroDivisionError: integer division or modulo by zero
Ceci est dû en partie au fait qu’il n’existe pas de vérificateur de type statique (généralement utile) pour python. Une fonction python ne peut pas indique syntaxiquement, au moment de la compilation, qu’elle a un codomaine particulier; il n'y a aucun moyen de forcer les appelants à faire correspondre tous les cas dans le type de retour de la fonction.
Si vous préférez, vous pouvez écrire (de façon non pythonique) un wrapper Maybe:
class Maybe(object):
def get_or_else(self, default):
return self.vaue if isinstance(self, Just) else default
class Just(Maybe):
def __init__(self, value):
self.value = value
class Nothing(Maybe):
pass
Mais je ne le ferais pas, à moins d’essayer de porter quelque chose de scala en python sans trop changer.
mypy
ajoute des définitions de type et une vérification de type (pas au moment de l'exécution) sur Python normal. Ils ont une Optional
: https://docs.python.org/3/library/typing.html#typing.Optional . Plus ici/ https://www.python.org/dev/peps/pep-0484/#rationale-and-goals . Intellij a un support de plugin qui rend le tout très professionnel et fluide.
En python, pour une absence de valeur, la variable est None, vous pouvez donc le faire de cette façon.
vars = None
vars = myfunction()
if vars is None:
print 'No value!'
else:
print 'Value!'
ou même juste vérifier si une valeur est présente comme ceci
if vars is not None:
print vars
Je me rends compte que la fête a pris beaucoup de retard, mais je suis arrivé sur cette page au-dessus de Google avant de décider de la mettre en œuvre, alors je pourrais peut-être aider les autres à googler avec ça. Je l’ai implémenté, vous pouvez l’obtenir de pypi sous la forme pyther-maybe
, il implémente à la fois Either et Maybe avec peut-être en tant que sous-classe spéciale de Either. Cet exemple devrait expliquer comment cela fonctionne:
import sys
from pyther_maybe import *
def save_div ( x, y ):
if y == 0:
return nothing() # alias of Maybe()
else:
return value(x / y) # alias of Maybe(x / y)
float_test = save_div(1.0, 3.0)
assert isinstance(float_test, Maybe)
if float_test: #nothing tests as false:
float = float_test() # calling the container with no arguments returns its value
else:
sys.exit("something went wrong")
print float
# or if you want to encode a reason:
def save_div ( x, y ):
if y == 0:
return left("You can't divide by zero, silly") # alias of Either(left=...)
else:
return right(x / y) # alis of Either(...)
float_test = save_div(4.2, 0.0)
assert isinstance(float_test, Either)
def fake_exit ( string ):
print "We would have exited with:"
print string
return "Whatever value"
if float_test:
# these two are te same
float = float_test()
float = float_test.right()
else:
fake_exit(float_test.left())
# or in a shorter and more pleasant format
# does the same as above
float = float_test.extract(fake_exit)
print float # prints "Whatever value"
# Also, these containers are mutable:
box = nothing()
try:
print box() # raises exception
except RightEitherException:
print "We caught an exception"
def change_box():
box(4)
change_box()
print box() # 4
Il a plus de fonctionnalités que cela, dont certaines sont plutôt inutiles dans la pratique (c'est aussi un itérateur, par exemple, avec une notation en indice telle que pyther_maybe.either(x)[pyther_maybe.Right] == x
.
Une liste dont la longueur est toujours égale à zéro ou un remplit certains des mêmes objectifs que les types facultatif/peut-être. Vous n'obtiendrez pas les avantages du typage statique en Python, mais vous obtiendrez probablement une erreur d'exécution même sur le chemin d'accès content si vous écrivez du code qui tente d'utiliser le "peut-être" sans le "décompresser" explicitement.