В некоторых случаях использование 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.