Optional: Object wrapper for handling errors

class carriage.Optional

An type for handling special value or exception.

Here is a contacts data constructed with multiple levels dictionary.

>>> contacts = {
...     'John Doe': {
...         'phone': '0911-222-333',
...         'address': {'city': 'hsinchu',
...                     'street': '185 Somewhere St.'}},
...     'Richard Roe': {
...         'phone': '0933-444-555',
...         'address': {'city': None,
...                     'street': None}},
...     'Mark Moe': {
...         'address': None},
...     'Larry Loe': None
... }

If we need a function to get the formatted city name of some contact, we will have a lot of nested if statement for handling None or other unexpected values.

>>> def get_city(name):
...     contact = contacts.get(name)
...     if contact is not None:
...         address = contact.get('address')
...         if address is not None:
...             city = address.get('city')
...             if city is not None:
...                 return f'City: {city}'
...     return 'No city available'
>>> get_city('John Doe')
'City: hsinchu'
>>> get_city('Richard Roe')
'No city available'
>>> get_city('Mark Moe')
'No city available'
>>> get_city('Larray Loe')
'No city available'
>>> get_city('Not Existing')
'No city available'

Optional is useful on handling unexpected return values or exceptions and makes the code shorter and more readable.

>>> def getitem_opt(obj, key):
...     """The same as Optional.from_getitem()"""
...     try:
...         return Some(obj[key])
...     except (KeyError, TypeError):
...         return Nothing
>>> def get_city2(name):
...     return (getitem_opt(contacts, name)
...             .and_then(lambda contact: getitem_opt(contact, 'address'))
...             .and_then(lambda address: getitem_opt(address, 'city'))
...             .filter(lambda city: city is not None)
...             .map(lambda city: f'City: {city}')
...             .get_or('No city available')
...             )
>>> get_city2('John Doe')
'City: hsinchu'
>>> get_city2('Richard Roe')
'No city available'
>>> get_city2('Mark Moe')
'No city available'
>>> get_city2('Larray Loe')
'No city available'
>>> get_city('Not Existing')
'No city available'

Create Optional directly

>>> Some(3)
>>> Nothing

Create Optional by calling a function that may throw exception

>>> def divide(a, b):
...     return a / b
>>> Optional.from_call(divide, 2, 4, errors=ZeroDivisionError)
>>> Optional.from_call(divide, 2, 0, errors=ZeroDivisionError)

Create Optional from a value that may be None or other spectial value.

>>> adict = {'a': 1, 'b': 2, 'c': 3}
>>> Optional.from_value(adict.get('c'), nothing_value=None)
>>> Optional.from_value(adict.get('d'), nothing_value=None)

Return optional_func(value) if it is Some optional_func should return Optional

and_then is useful for chaining functions that return Optional


Return Nothing if Some doesn’t satisfy the predicate

classmethod from_call(func, *args, errors=(<class 'Exception'>, ), **kwargs)

Create an Optional by calling a function

return Nothing if exception is raised

classmethod from_getattr(obj, attr_name)

Create an Optional by calling obj.attr_name

return Nothing if AttributeError is raised

classmethod from_getitem(obj, key)

Create an Optional by calling obj[key]

return Nothing if KeyError or TypeError is raised

classmethod from_value(value, nothing_value=None)

Create an Optional from a value

return Nothing if value equals to nothing_value


Get the value if it is Some or get default if it is Nothing


Get the value if it is Some or get None if it is Nothing


Check if it is Nothing


Check if it is Some


Return Some(func(value)) if it is Some


Get the value if it is Some or raise AttributeError if it is not