it-swarm.com.ru

Есть ли Python-эквивалент для Scala's Option или Either?

Мне очень нравится использовать Option и Either monads в Scala. Есть ли какой-нибудь эквивалент для этих вещей в Python? Если нет, то каков Pythonic способ обработки ошибок или «отсутствия значения» без исключения?

27
Melvic Ybanez

Ну, на самом деле, Pythonic для функции сказать: «Я не определен на этом этапе» - это вызвать исключение. 

>>> 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

Это отчасти потому, что для python нет (как правило, полезной) статической проверки типов. Функция Python не может синтаксически заявить во время компиляции, что она имеет определенный кодомен; нет никакого способа заставить вызывающих абонентов соответствовать всем случаям в типе возвращаемого значения функции.

Если вы предпочитаете, вы можете написать (нетипично) обертку 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

Но я бы не стал этого делать, если вы не пытаетесь портировать что-то из scala в python, не сильно меняя

14
SingleNegationElimination

mypy добавляет определения типов и проверку типов (не во время выполнения) поверх обычного Python. У них есть Optional: https://docs.python.org/3/library/typing.html#typing.Optional . Подробнее здесь https://www.python.org/dev/peps/pep-0484/#rationale-and-goals . Intellij имеет поддержку плагинов, что делает его очень профессиональным и плавным.

8
SemanticBeeng

В python для отсутствия значения переменная равна None, поэтому вы можете сделать это следующим образом.

vars = None

vars = myfunction()

if vars is None:
     print 'No value!'
else:
     print 'Value!'

или даже просто проверить, присутствует ли значение, как это

if vars is not None:
     print vars
7
jordsti

Я понимаю, что это довольно поздно для вечеринки, но я пришел на эту страницу в верхней части Google, прежде чем принять решение о ее реализации, так что, возможно, я могу помочь другим в поиске Google Я реализовал это, вы можете получить его из pypi как pyther-maybe, он реализует как Either, так и Maybe с Maybe в качестве специального подкласса Either. Этот пример должен объяснить, как это работает:

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

Он имеет больше возможностей, чем некоторые, некоторые из которых довольно бесполезны на практике (например, он также является итератором и имеет нижнюю запись, такую ​​как pyther_maybe.either(x)[pyther_maybe.Right] == x).

5
Zorf

Список, который всегда имеет нулевую длину или один, выполняет некоторые из тех же целей, что и необязательные/возможно типы. Вы не получите преимуществ статической типизации в Python, но, вероятно, получите ошибку во время выполнения даже на счастливом пути, если напишите код, который пытается использовать «может быть» без явного «развертывания» его.

1
Adam L. Taylor