Делаем Java-подобный Optional в Python

Опубликовано 25 November 2016 в Python

В некоторых случаях использование None может превратить код в нечитаемую и неподдерживаемую кашу. К примеру, если есть необходимость отличить "пустое" значение от отсутствия значения для целочисленного ввода, когда 0 не может использоваться в качестве этого "пустого" значения, обойтись только используя None очень сложно. Одно из возможных значений использовать что-то подобное Optional из Java.

Конечно, Optional не совсем "питонячий путь". В некоторых случаях можно использовать исключения, как предлагается в этой дискуссии на StackOverflow.

В моем случае это не работало. Так что я решил сделать свою имплементацию Optional. И в итоге я получил чистый и хорошо читаемый код. После дискуссии с коллегами, мы решили использовать имена из Haskell, так как то, что у меня получилось больше походило на хаскелльный тип Maybe, чем на джавовый Optional. Вот что у меня получилось:

from abc import ABCMeta, abstractmethod

class Maybe(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def get(self, default=None):
        pass


class Just(Maybe):
    def __init__(self, value):
        self.value = value

    def __nonzero__(self):
        return True

    def get(self, default=None):
        return self.value


class Nothing(Maybe):
    def __nonzero__(self):
        return False

    def get(self, default=None):
        return default

После интеграции в существующий кода, я могу с уверенностью сказать, что решение работает идеально. Возможно, надо бы добавить еще красивое представление для этих объектов. Но в целом даже без этого с объектами типа Maybe очень удобно работать при отладке: в отличие от None, понятно что из себя представляет то или иное значение.

Если нужно что-то более сложное, попробуйте hask. Но будьте готовы к тому, что у них слишком много хаскелля в их питоне.

Если мой подход кажется не самым удачным, можно попробовать и другие. К примеру, почерпнутых из статьи Python Option Types.

---
Возник вопрос? Мне всегда можно написать в Twitter: avkorablev