Maybe

The Maybe container is used when a series of computations could return None at any point.

Maybe container

Maybe consist of two types: Some and Nothing. We have a convenient method to create different Maybe types based on just a single value:

>>> from returns.maybe import Maybe

>>> str(Maybe.new(1))
'<Some: 1>'

>>> str(Maybe.new(None))
'<Nothing>'

Usage

It might be very useful for complex operations like the following one:

>>> from attr import dataclass
>>> from typing import Optional
>>> from returns.maybe import Maybe

>>> @dataclass
... class Address(object):
...     street: Optional[str]

>>> @dataclass
... class User(object):
...     address: Optional[Address]

>>> @dataclass
... class Order(object):
...    user: Optional[User]

>>> def get_street_adderess(order: Order) -> Maybe[str]:
...     return Maybe.new(order.user).map(
...         lambda user: user.address,
...     ).map(
...         lambda address: address.street,
...     )
...

>>> with_address = Order(User(Address('Some street')))
>>> empty_user = Order(None)
>>> empty_address = Order(User(None))
>>> empty_street = Order(User(Address(None)))

>>> str(get_street_adderess(with_address))  # all fields are not None
'<Some: Some street>'

>>> str(get_street_adderess(empty_user))
'<Nothing>'
>>> str(get_street_adderess(empty_address))
'<Nothing>'
>>> str(get_street_adderess(empty_street))
'<Nothing>'

Optional type

One may ask: “How is that different to the Optional[] type?” That’s a really good question!

Consider the same code to get the street name without Maybe and using raw Optional values:

order: Order  # some existing Order instance
street: Optional[str] = None
if order.user is not None:
    if order.user.address is not None:
        street = order.user.address.street

It looks way uglier and can grow even more uglier and complex when new logic will be introduced.

Decorators

Limitations

Typing will only work correctly if decorator_plugin is used. This happens due to mypy issue.

maybe

Sometimes we have to deal with functions that dears to return Optional values!

We have to work with it the carefully and write if x is not None: everywhere. Luckily, we have your back! maybe function decorates any other function that returns Optional and converts it to return Maybe instead:

>>> from typing import Optional
>>> from returns.maybe import Maybe, maybe

>>> @maybe
... def number(num: int) -> Optional[int]:
...     if num > 0:
...         return num
...     return None

>>> result: Maybe[int] = number(1)
>>> str(result)
'<Some: 1>'

FAQ

How can I turn Maybe into Optional again?

When working with regular Python, you might need regular Optional[a] values.

You can easily get one from your Maybe container at any point in time:

>>> from returns.maybe import Maybe
>>> assert Maybe.new(1).value_or(None) == 1
>>> assert Maybe.new(None).value_or(None) is None

As you can see, revealed type of .value_or(None) is Optional[a]. Use it a fallback.

Why there’s no IOMaybe?

We do have IOResult, but we don’t have IOMaybe. Why? Because when dealing with IO there are a lot of possible errors. And Maybe represents just None and the value.

It is not useful for IO related tasks. So, use Result instead, which can represent what happened to your IO.

You can convert Maybe to Result and back again with special Converters.

API Reference

graph TD; Maybe _Some _Nothing BaseContainer --> Maybe Generic --> Maybe Maybe --> _Nothing Maybe --> _Some
class Maybe(inner_value)[source]

Bases: returns.primitives.container.BaseContainer, typing.Generic

Represents a result of a series of commutation that can return None.

An alternative to using exceptions or constant is None checks. Maybe is an abstract type and should not be instantiated directly. Instead use Some and Nothing.

success_type

alias of _Some

failure_type

alias of _Nothing

classmethod new(inner_value)[source]

Creates new instance of Maybe container based on a value.

>>> from returns.maybe import Maybe, Some, Nothing
>>> assert Maybe.new(1) == Some(1)
>>> assert Maybe.new(None) == Nothing
Return type

Maybe[+_ValueType]

map(function)[source]

Composes successful container with a pure function.

>>> from returns.maybe import Some, Nothing
>>> def mappable(string: str) -> str:
...      return string + 'b'
...
>>> assert Some('a').map(mappable) == Some('ab')
>>> assert Nothing.map(mappable) == Nothing
Return type

Maybe[~_NewValueType]

bind(function)[source]

Composes successful container with a function that returns a container.

>>> from returns.maybe import Nothing, Maybe, Some
>>> def bindable(string: str) -> Maybe[str]:
...      return Some(string + 'b')
...
>>> assert Some('a').bind(bindable) == Some('ab')
>>> assert Nothing.bind(bindable) == Nothing
Return type

Maybe[~_NewValueType]

value_or(default_value)[source]

Get value from succesful container or default value from failed one.

>>> from returns.maybe import Nothing, Some
>>> assert Some(0).value_or(1) == 0
>>> assert Nothing.value_or(1) == 1
Return type

Union[+_ValueType, ~_NewValueType]

unwrap()[source]

Get value from successful container or raise exception for failed one.

>>> from returns.maybe import Nothing, Some
>>> assert Some(1).unwrap() == 1
>>> Nothing.unwrap()
Traceback (most recent call last):
  ...
returns.primitives.exceptions.UnwrapFailedError
Return type

+_ValueType

failure()[source]

Get failed value from failed container or raise exception from success.

>>> from returns.maybe import Nothing, Some
>>> assert Nothing.failure() is None
>>> Some(1).failure()
Traceback (most recent call last):
  ...
returns.primitives.exceptions.UnwrapFailedError
Return type

None

classmethod lift(function)[source]

Lifts function to be wrapped in Maybe for better composition.

In other words, it modifies the function’s signature from: a -> b to: Maybe[a] -> Maybe[b]

Works similar to map(), but has inverse semantics.

This is how it should be used:

>>> from returns.maybe import Maybe, Nothing, Some
>>> def example(argument: int) -> float:
...     return argument / 2
...
>>> assert Maybe.lift(example)(Some(2)) == Some(1.0)
>>> assert Maybe.lift(example)(Nothing) == Nothing
Return type

Callable[[Maybe[+_ValueType]], Maybe[~_NewValueType]]

Some(inner_value)[source]

Public unit function of protected _Some type.

>>> from returns.maybe import Some, Nothing
>>> str(Some(1))
'<Some: 1>'
>>> assert Some(None) == Nothing
Return type

Maybe[+_ValueType]

Nothing = <returns.maybe._Nothing object>

Public unit value of protected _Nothing type.

maybe(function)[source]

Decorator to covert None returning function to Maybe container.

Supports both async and regular functions.

>>> from typing import Optional
>>> from returns.maybe import Nothing, Some, maybe

>>> @maybe
... def might_be_none(arg: int) -> Optional[int]:
...     if arg == 0:
...         return None
...     return 1 / arg
...
>>> assert might_be_none(0) == Nothing
>>> assert might_be_none(1) == Some(1.0)