API reference¶

Maybe¶

cans.Maybe¶

A container which contains either one item, or none. Use Just and Nothing to express these two variants. When type annotating, only use Maybe.

>>> a: Maybe[int] = Just(5)
>>> b: Maybe[str] = Nothing()
...
>>> def parse(s: str) -> Maybe[int]:
...     try: return Just(int(s))
...     except ValueError: return Nothing()
...
>>> def first(m: list[T]) -> Maybe[T]:
...     return Just(m[0]) if m else Nothing()
...
>>> parse("42")
Just(42)
>>> first([])
Nothing()

Various methods are available (documented in _MaybeMixin) which you can use to operate on the value, without repeatedly unpacking it.

>>> first(["-5", "6", ""]).flatmap(parse).map(abs)
Just(5)
>>> first([]).flatmap(parse).map(abs).unwrap_or("Nothing here...")
"Nothing here..."

In Python 3.10+, you can use pattern matching to deconstruct a Maybe.

>>> match first(["bob", "henry", "anita"]).map(str.title):
...     case Just(x):
...         print(f'Hello {x}!')
...     case Nothing()
...         print('Nobody here...')
"Hello Bob!"

Maybe also implements the Sequence API, meaning it acts kind of like a list with one or no items. Thus, it works nicely with itertools!

>>> from itertools import chain
>>> list(chain.from_iterable(map(parse, "a4f59b")))
[4, 5, 9]

alias of Union[cans.Just[T], cans.Nothing[T]]

class cans.Just(_value: T)[source]¶

The version of Maybe which contains a value.

Example

>>> a: Maybe[int] = Just(-8)
>>> a.map(abs).unwrap()
8
class cans.Nothing[source]¶

The version of Maybe which does not contain a value.

Example

>>> a: Maybe[int] = Nothing()
>>> a.map(abs).unwrap_or("nope")
"nope"
cans.flatten(m: Maybe[Maybe[T]]) → Maybe[T][source]¶

Flatten two nested maybes.

Example

>>> flatten(Just(Just(5)))
Just(5)
>>> flatten(Just(Nothing()))
Nothing()
>>> flatten(Nothing())
Nothing()
cans.maybe_from_optional(_v: Optional[T]) → Maybe[T][source]¶

Create a maybe container from the given value, which may be None. In that case, it’ll be an empty Maybe.

Example

>>> maybe_from_optional(5)
Just(5)
>>> maybe_from_optional(None)
Nothing()
class cans._MaybeMixin[source]¶

Bases: Generic[cans.T], Sequence[cans.T]

Collection of methods supported by both Just and Nothing.

unwrap() → T[source]¶

Unwrap the value in this container. If there is no value, TypeError is raised.

Example

>>> Just(6).unwrap()
6
>>> Nothing().unwrap()
Exception: TypeError()

Tip

Only use this if you’re absolutely sure that there is a value. If not, use unwrap_or() instead. Or, use expect() for a more descriptive message.

unwrap_or(_default: V) → Union[T, V][source]¶

Unwrap the value in this container. If there is no value, return the given default.

Example

>>> Just(8).unwrap_or("foo")
8
>>> Nothing().unwrap_or("foo")
"foo"
expect(_msg: str) → T[source]¶

Unwrap the value in this container. If there is no value, raise an AssertionError with message

>>> Just(9).expect("What on earth?")
9
>>> Nothing().expect("What did you expect?")
Exception: AssertionError("What did you expect?")
is_just() → bool[source]¶

True if this Maybe contains a value

Example

>>> Just(2).is_just()
True
>>> Nothing().is_just()
False
is_nothing() → bool[source]¶

True if this Maybe does not contain a value

Example

>>> Just(2).is_nothing()
False
>>> Nothing().is_nothing()
True
map(_func: Callable[[T], U]) → Maybe[U][source]¶

Apply a function to the value inside the Maybe, without unwrapping it.

Example

>>> Just("hello").map(str.upper)
Just("HELLO")
>>> Nothing().map(abs)
Nothing()
filter(_func: Callable[[T], bool]) → Maybe[T][source]¶

Keep the value inside only if it satisfies the given predicate.

Example

>>> Just("9").filter(str.isdigit)
Just("9")
>>> Just("foo").filter(str.isdigit)
Nothing()
>>> Nothing().filter(str.isdigit)
Nothing()
zip(_other: Maybe[U]) → Maybe[Tuple[T, U]][source]¶

Combine two values in a tuple, if both are present.

Example

>>> Just(8).zip(Just(2))
Just((8, 2))
>>> Just(7).zip(Nothing())
Nothing()
>>> Nothing().zip(Just(3))
Nothing()
>>> Nothing().zip(Nothing())
Nothing()
flatmap(_func: Callable[[T], Maybe[U]]) → Maybe[U][source]¶

Apply a function (which returns a maybe) to the value inside the Maybe. Then, flatten the result.

Example

>>> def first(s) -> Maybe:
...     try:
...          return Just(s[0])
...     except LookupError:
...          return Nothing()
...
>>> Just([9, 4]).flatmap(first)
Just(9)
>>> Just([]).flatmap(first)
Nothing()
>>> Nothing().flatmap(first)
Nothing()
as_optional() → Optional[T][source]¶

Convert the value into an possibly-None value.

Example

>>> Just(6).as_optional()
6
>>> Nothing().as_optional()
None
setdefault(_v: V) → Maybe[Union[T, V]][source]¶

Set a value if one is not already present.

Example

>>> Just(6).setdefault(7)
Just(6)
>>> Nothing().setdefault(3)
Just(3)
and_(_other: Maybe[U]) → Maybe[Union[T, U]][source]¶

Perform a logical AND operation. Returns the first Nothing, or the last of the two values.

Tip

Available as the and_() method as well as the & operator.

Example

>>> Just(5) & Just(9)
Just(9)
>>> Just(5).and_(Just(9))
Just(9)
>>> Just(9) & Nothing()
Nothing()
>>> Nothing() & Just(8)
Nothing()
__and__(_other: Maybe[U]) → Maybe[Union[T, U]]¶

Perform a logical AND operation. Returns the first Nothing, or the last of the two values.

Tip

Available as the and_() method as well as the & operator.

Example

>>> Just(5) & Just(9)
Just(9)
>>> Just(5).and_(Just(9))
Just(9)
>>> Just(9) & Nothing()
Nothing()
>>> Nothing() & Just(8)
Nothing()
or_(_other: Maybe[U]) → Maybe[Union[T, U]][source]¶

Perform a logical OR operation. Return the first Just, or the last of the two values.

Tip

Available as the or_() method as well as the | operator.

Example

>>> Just(5) | Just(9)
Just(5)
>>> Just(5).or_(Just(9))
Just(5)
>>> Just(9) | Nothing()
Just(9)
>>> Nothing() | Just(8)
Just(8)
>>> Nothing() | Nothing()
Nothing()
__or__(_other: Maybe[U]) → Maybe[Union[T, U]]¶

Perform a logical OR operation. Return the first Just, or the last of the two values.

Tip

Available as the or_() method as well as the | operator.

Example

>>> Just(5) | Just(9)
Just(5)
>>> Just(5).or_(Just(9))
Just(5)
>>> Just(9) | Nothing()
Just(9)
>>> Nothing() | Just(8)
Just(8)
>>> Nothing() | Nothing()
Nothing()
__iter__() → Iterator[T][source]¶

Iterate over the contained item, if present.

Example

>>> list(Just(5))
[5]
>>> list(Nothing())
[]
__contains__(_v: object) → bool[source]¶

Check if the item is contained in this object.

Example

>>> 5 in Just(5)
True
>>> 4 in Just(8)
False
>>> 1 in Nothing()
False
__len__() → int[source]¶

The number of items contained (0 or 1)

Example

>>> len(Just(5))
1
>>> len(Nothing())
0
__getitem__(_i: int) → T[source]¶
__getitem__(_i: slice) → Maybe[T]

Get the item from this container by index. Part of the Sequence API.

Behaves similarly to a list of one or zero items.

Example

>>> Just(6)[0]
6
>>> Just(8)[8]
Exception: IndexError
>>> Nothing()[0]
Exception: IndexError
...
>>> Just(6)[:]
Just(6)
>>> Just(2)[:9:4]
Just(2)
>>> Just(7)[2:]
Nothing()
>>> Nothing()[:]
Nothing()
>>> Nothing()[2:9:5]
Nothing()