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

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

В моём случае это не работало. Так что я решил сделать свою реализацию 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.

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