1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
Helper functions
================
We feature several helper functions to make your developer experience better.
compose
-------
We also ship an utility function to compose two different functions together.
.. code:: python
>>> from returns.functions import compose
>>> bool_after_int = compose(int, bool)
>>> assert bool_after_int('1') is True
>>> assert bool_after_int('0') is False
Composition is also type-safe.
The only limitation is that we only support
functions with one argument and one return to be composed.
Only works with regular functions (not async).
.. warning::
``compose`` might fail to infer types for some functions.
There are several problems: ``lambda`` and generic functions.
In these cases ``mypy`` will fail to infer
the types of the resulting function.
In this case, use :func:`pipe <returns._internal.pipeline.pipe.pipe>`
it does the same thing, but has pretty good type inference.
Or use manual annotations with ``Callable`` type.
identity
--------
We also ship :func:`returns.functions.identity` function
to help you with the composition.
Identity function is a simple concept: it just returns its argument.
If you wonder why do we need this function, please read below:
- `Practical Usage of Identity Function <https://blog.bigbinary.com/2018/03/20/practical-usage-of-identity-function.html>`_ (JS)
- `Using Identity Functions <https://emilvarga.com/posts/2016/08/01/using-identity-functions>`_ (Scala)
tap and untap
-------------
We need ``tap()`` function to easily compose values
with functions that does not return.
For example you sometimes need to ``print()`` values inside your :ref:`pipe`:
.. code:: python
>>> from returns.functions import tap
>>> result = tap(print)(1) # will print and return 1
1
>>> assert result == 1
You can also use the ``untap`` function to turn any function's
return type to ``None`` and still do its thing:
.. code:: python
>>> from returns.functions import tap, untap
>>> result = untap(tap(print))(1) # will print and return None
1
>>> assert result is None
This is also sometimes helpful for a typed function composition.
raise_exception
---------------
Sometimes you really want to reraise an exception from ``Failure[Exception]``
due to some existing API (or a dirty hack).
We allow you to do that with ease!
.. code:: python
from returns.functions import raise_exception
def create_account_and_user(username: str) -> ...:
"""
Creates new Account-User pair.
Imagine, that you need to reraise ValidationErrors due to existing API.
"""
return _validate_user(
username,
).alt(
# What happens here is interesting, since you do not let your
# unwrap to fail with UnwrapFailedError, but instead
# allows you to reraise a wrapped exception.
# In this case `ValidationError()` will be thrown
# before `UnwrapFailedError`
raise_exception,
)
def _validate_user(username: str) -> Result['User', ValidationError]:
...
Use this with caution. We try to remove exceptions from our code base.
Original proposal is `here <https://github.com/dry-python/returns/issues/56>`_.
not\_
-----
With ``not_`` helper function we can easily deny a function returns.
It supports functions with one or more arguments.
.. code:: python
>>> from typing import List
>>> from returns.functions import compose, not_
>>> def is_even(number: int) -> bool:
... return number % 2 == 0
>>> def number_is_in_list(number: int, list_: List[int]) -> bool:
... return number in list_
>>> assert not_(is_even)(2) is False
>>> assert not_(number_is_in_list)(1, [2, 3, 4]) is True
>>> assert compose(int, not_(is_even))("1") is True
API Reference
-------------
.. automodule:: returns.functions
:members:
|