sidekick.functions
¶
The functions in this module are responsible for creating, transforming,
composing and introspecting other functions. Some of those functions might
be familiar from the standard lib’s functools module. In spite of
those similarities, this module is not a drop-in replacement of the
standard lib’s functools
module.
This module also exposes the fn
type, that extends standard
Python functions with new methods and operators. This extended function
behavior is applied to most sidekick’s functions and can be easily
re-used to extend user code.
Function introspection and conversion¶
Stub |
Represent a function declaration Stub. |
arity |
Return arity of a function. |
signature |
Return the signature of a function. |
stub |
Return a Stub object representing the function signature. |
to_callable (func) |
Convert argument to callable. |
to_function (func[, name]) |
Return object as as Python function. |
to_fn (func) |
Convert callable to an fn object. |
Partial application¶
curry (n[, func]) |
Return the curried version of a function of n arguments. |
partial (*args, **kwargs) |
Return a new function that partially apply the given arguments and keywords. |
rpartial (func, *args, **kwargs) |
Partially apply arguments from the right. |
method |
Return a function that calls a method of its argument with the given values. |
Composition¶
compose |
Create function that apply argument from right to left. |
pipe |
Pipe a value through a sequence of functions. |
pipeline |
Similar to compose, but order of application is reversed. |
thread |
Similar to pipe, but accept extra arguments to each function in the pipeline. |
rthread |
Like thread, but data is passed as last argument to functions, instead of first. |
thread_if |
Similar to thread, but each form must be a tuple with (test, fn, …args) and only pass the argument to fn if the boolean test is True. |
rthread_if |
Similar to rthread, but each form must be a tuple with (test, fn, …args) and only pass the argument to fn if the boolean test is True. |
juxt |
Juxtapose several functions. |
Combinators¶
identity |
The identity function. |
ridentity |
Return last positional argument. |
always |
Return a function that always return x when called with any number of arguments. |
rec |
Fix func first argument as itself. |
trampoline |
Decorator that implements tail call elimination via the trampoline technique. |
value |
Evaluate argument, if it is a function or return it otherwise. |
call (*args, **kwargs) |
Return a function caller. |
do |
Runs func on x , returns x . |
Runtime control¶
once |
Limit function to a single invocation. |
thunk |
A thunk that represents a lazy computation. |
call_after |
Creates a function that invokes func once it’s called more than n times. |
call_at_most |
Creates a function that invokes func while it’s called less than n times. |
throttle |
Limit the rate of execution of func to once at each dt seconds. |
background |
Return a function that executes in the background. |
error |
Raises the given exception. |
raising |
Creates function that raises the given exception. |
retry |
Retry to execute function at least n times before raising an error. |
catch |
Handle exception in function. |
Transform arguments¶
flip |
Flip the order of arguments in a binary operator. |
select_args |
Creates a function that calls func with the arguments reordered. |
keep_args |
Uses only the first n positional arguments to call func. |
reverse_args |
Creates a function that invokes func with the positional arguments order reversed. |
skip_args |
Skips the first n positional arguments before calling func. |
splice_args |
Return a function that receives a sequence as single argument and splice them into func. |
variadic_args |
Return a function that receives variadic arguments and pass them as a tuple to func. |
API reference¶
-
class
sidekick.functions.
fn
(func)[source]¶ Base class for function-like objects in Sidekick.
-
curry
(arity, func=None, **kwargs) → Union[sidekick.functions.fn.Curried, callable][source]¶ Return a curried function with given arity.
-
generator
¶ Decorates generator function to return a sidekick iterator instead of a regular Python generator.
Examples
>>> @sk.generator ... def fibonacci(): ... x = y = 1 ... while True: ... yield x ... x, y = y, x + y >>> fibonacci() sk.iter([1, 1, 2, 3, 5, 8, ...])
-
partial
(*args, **kwargs)[source]¶ Return a fn-function with all given positional and keyword arguments applied.
-
result
(*args, **kwargs)[source]¶ Return a result instance after function call.
Exceptions are converted to Err() cases.
-
single
(*args, **kwargs)[source]¶ Similar to partial, but with a few constraints:
- Resulting function must be a function of a single positional argument.
- Placeholder expressions are evaluated passing this single argument to the resulting function.
Example
>>> add = fn(lambda x, y: x + y) >>> g = add.single(_, 2 * _) >>> g(10) # g(x) = x + 2 * x 30
Returns: fn
-
-
sidekick.functions.
quick_fn
(func: callable) → sidekick.functions.fn.fn[source]¶ Faster fn constructor.
This is about twice as fast as the regular fn() constructor. It assumes that fn is
-
class
sidekick.functions.
Stub
[source]¶ Represent a function declaration Stub.
-
count
()¶ Return number of occurrences of value.
-
index
()¶ Return first index of value.
Raises ValueError if the value is not present.
-
name
¶ Alias for field number 0
-
signatures
¶ Alias for field number 1
-
-
sidekick.functions.
arity
[source]¶ Return arity of a function.
Examples
>>> from operator import add >>> sk.arity(add) 2
-
sidekick.functions.
to_function
(func: Any, name=None) → function[source]¶ Return object as as Python function.
Non-functions are wrapped into a function definition.
-
sidekick.functions.
to_callable
(func: Any) → Callable[source]¶ Convert argument to callable.
This differs from to_function in which it returns the most efficient version of object that has the same callable interface as the argument.
This removes sidekick’s function wrappers such as fn and try to convert argument to a straightforward function value.
This defines the following semantics:
- Sidekick’s fn: extract the inner function.
- None: return the identity function.
- Mappings: map.__getitem__
- Functions, methods and other callables: returned as-is.
-
sidekick.functions.
to_fn
(func: Any) → sidekick.functions.fn.fn[source]¶ Convert callable to an
fn
object.If func is already an
fn
instance, it is passed as is.
-
sidekick.functions.
curry
(n, func=None)[source]¶ Return the curried version of a function of n arguments.
Curried functions return partial applications of the function if called with missing arguments:
>>> add = sk.curry(2, lambda x, y: x + y)
We can call a function two ways:
>>> add(1, 2) == add(1)(2) True
This is useful for building simple functions from partial application
>>> succ = add(1) >>> succ(2) 3
curry()
is itself a curried function, hence it can be called as>>> add = sk.curry(2)(lambda x, y: x + y)
or equivalently as a decorator
>>> @sk.curry(2) ... def add(x, y): ... return x + y
Currying usually requires functions of fixed number of arguments (the number of arguments is called the arity of a function). We can control how many arguments participate in the auto-currying by passing the arity number as the first argument to the
curry()
function.Variadic functions are accepted, and arity is understood as the minimum number of arguments necessary to invoke the function. The caller can, however, specify additional arguments.
But it accepts more than 2 arguments, if needed. (Notice that only the first two arguments auto-curry.)
>>> add = sk.curry(2, lambda *args: sum(args)) >>> add(1, 2, 3, 4) 10
Sometimes we don’t want to specify the arity of a function or don’t want to think too much about it.
curry()
accepts'auto'
as an arity specifier that makes it try to infer the arity automatically. Under the hood, it just callsarity()
to obtain the correct value.Sidekick curries most functions where it makes sense. Variadic functions cannot be curried if the extra arguments can be passed by position. This decorator inspect the decorated function to determine if it can be curried or not.
-
sidekick.functions.
partial
(*args, **kwargs) → sidekick.functions.fn.fn[source]¶ Return a new function that partially apply the given arguments and keywords.
Additional positional and keyword arguments after partially applied to function
Parameters: func – Function or func-like object. Examples
>>> from operator import add >>> incr = sk.partial(add, 1) >>> incr(41) 42
See also
-
sidekick.functions.
rpartial
(func: Optional[Callable], *args, **kwargs) → sidekick.functions.fn.fn[source]¶ Partially apply arguments from the right.
Examples
>>> from operator import truediv as div >>> half = sk.rpartial(div, 2) >>> half(42) 21.0
See also
-
sidekick.functions.
method
[source]¶ Return a function that calls a method of its argument with the given values.
A method caller object. It can be used as a function
>>> pop_first = sk.method("pop", 0) >>> pop_first([1, 2, 3]) 1
or as a function factory.
>>> pop_first = sk.method.pop(0) >>> pop_first([1, 2, 3]) 1
The second usage is syntactically cleaner and prevents the usage of invalid Python names. All method calls performed in the
sk.method
object returns the corresponding methodcaller function.
-
sidekick.functions.
compose
[source]¶ Create function that apply argument from right to left.
compose(f, g, h, …) ==> f << g << h << …Example
>>> f = sk.compose((X + 1), (X * 2)) >>> f(2) # double than increment 5
See also
-
sidekick.functions.
pipe
[source]¶ Pipe a value through a sequence of functions.
I.e.
pipe(data, f, g, h)
is equivalent toh(g(f(data)))
or todata | f | g | h
, iff, g, h
are fn objects.Examples
>>> from math import sqrt >>> sk.pipe(-4, abs, sqrt) 2.0
See also
-
sidekick.functions.
pipeline
[source]¶ Similar to compose, but order of application is reversed.
pipeline(f, g, h, …) ==> f >> g >> h >> …Example
>>> f = sk.pipeline((X + 1), (X * 2)) >>> f(2) # increment and double 6
-
sidekick.functions.
thread
[source]¶ Similar to pipe, but accept extra arguments to each function in the pipeline.
Arguments are passed as tuples and the value is passed as the first argument.
Examples
>>> sk.thread(20, (op.div, 2), (op.mul, 4), (op.add, 2)) 42.0
-
sidekick.functions.
rthread
[source]¶ Like thread, but data is passed as last argument to functions, instead of first.
Examples
>>> sk.rthread(2, (op.div, 20), (op.mul, 4), (op.add, 2)) 42.0
-
sidekick.functions.
thread_if
[source]¶ Similar to thread, but each form must be a tuple with (test, fn, …args) and only pass the argument to fn if the boolean test is True.
If test is callable, the current value to the callable to decide if fn must be executed or not.
Like thread, Arguments are passed as tuples and the value is passed as the first argument.
Examples
>>> sk.thread_if(20, (True, op.div, 2), (False, op.mul, 4), (sk.is_even, op.add, 2)) 12.0
See also
-
sidekick.functions.
rthread_if
[source]¶ Similar to rthread, but each form must be a tuple with (test, fn, …args) and only pass the argument to fn if the boolean test is True.
If test is callable, the current value to the callable to decide if fn must be executed or not.
Like rthread, Arguments are passed as tuples and the value is passed as the last argument.
Examples
>>> sk.rthread_if(20, (True, op.div, 2), (False, op.mul, 4), (sk.is_even, op.add, 2)) 0.1
See also
-
sidekick.functions.
juxt
[source]¶ Juxtapose several functions.
Creates a function that calls several functions with the same arguments and return a tuple with all results.
It return a tuple with the results of calling each function. If last=True or first=True, return the result of the last/first call instead of a tuple with all the elements.
Examples
We can create an argument logger using either first/last=True
>>> sqr_log = sk.juxt(print, (X * X), last=True) >>> sqr_log(4) 4 16
Consume a sequence
>>> pairs = sk.juxt(next, next) >>> nums = iter(range(10)) >>> pairs(nums), pairs(nums) ((0, 1), (2, 3))
-
sidekick.functions.
identity
[source]¶ The identity function.
Return its first argument unchanged. Identity accepts one or more positional arguments and any number of keyword arguments.
Examples
>>> sk.identity(1, 2, 3, foo=4) 1
See also
-
sidekick.functions.
ridentity
[source]¶ Return last positional argument.
Similar to identity, but return the last positional argument and not the first. In the case the function receives a single argument, both identity functions coincide.
- Examples
>>> sk.ridentity(1, 2, 3) 3
See also
-
sidekick.functions.
always
[source]¶ Return a function that always return x when called with any number of arguments.
Examples
>>> f = sk.always(42) >>> f('answer', for_what='question of life, the universe ...') 42
-
sidekick.functions.
rec
[source]¶ Fix func first argument as itself.
This is a version of the Y-combinator and is useful to implement recursion from scratch.
Examples
In this example, the factorial receive a second argument which is the function it must recurse to. rec pass the function to itself so now the factorial only needs the usual numeric argument.
>>> sk.map( ... sk.rec(lambda f, n: 1 if n == 0 else n * f(f, n - 1)), ... range(10), ... ) sk.iter([1, 1, 2, 6, 24, 120, ...])
-
sidekick.functions.
power
(func: Optional[Callable], n: int) → sidekick.functions.fn.fn[source]¶ Return a function that applies f to is argument n times.
power(f, n)(x) ==> f(f(…f(x))) # apply f n times.Examples
>>> g = sk.power((2 * X), 3) >>> g(10) 80
-
sidekick.functions.
trampoline
[source]¶ Decorator that implements tail call elimination via the trampoline technique.
Parameters: func – A function that returns an args tuple to call it recursively or raise StopIteration when done. Examples
>>> @sk.trampoline ... def fat(n, acc=1): ... if n > 0: ... return n - 1, acc * n ... else: ... raise StopIteration(acc) >>> fat(5) 120
-
sidekick.functions.
call
(*args, **kwargs) → sidekick.functions.fn.fn[source]¶ Return a function caller.
Creates a function that receives another function and apply the given arguments.
Examples
>>> caller = sk.call(1, 2) >>> caller(op.add), caller(op.mul) (3, 2)
This function can be used as a decorator to declare self calling functions:
>>> @sk.call() ... def patch_module(): ... import builtins ... ... builtins.evil = lambda: print('Evil patch') ... return True
The variable
patch_module
will be assigned to the return value of the function and the function object itself will be garbage collected.
-
sidekick.functions.
value
[source]¶ Evaluate argument, if it is a function or return it otherwise.
Parameters: fn_or_value – Callable or some other value. If input is a callable, call it with the provided arguments and return. Otherwise, simply return. Examples
>>> sk.value(42) 42 >>> sk.value(lambda: 42) 42
-
sidekick.functions.
do
[source]¶ Runs
func
onx
, returnsx
.Because the results of
func
are not returned, only the side effects offunc
are relevant.Logging functions can be made by composing
do
with a storage function likelist.append
orfile.write
Examples
>>> log = [] >>> inc = sk.do(log.append) >> (X + 1) >>> [inc(1), inc(11)] [2, 12] >>> log [1, 11]
-
sidekick.functions.
once
[source]¶ Limit function to a single invocation.
Repeated calls to the function return the value of the first invocation.
Examples
This is useful to wrap initialization routines or singleton factories. >>> @sk.once … def configure(): … print(‘setting up…’) … return {‘status’: ‘ok’} >>> configure() setting up… {‘status’: ‘ok’}
See also
-
sidekick.functions.
thunk
[source]¶ A thunk that represents a lazy computation.
Python thunks are represented by zero-argument functions that compute the value of computation on demand and store it for subsequent invocations.
This function is designed to be used as a decorator.
Example
>>> @sk.thunk(host='localhost', port=5432) ... def db(host, port): ... print(f'connecting to SQL server at {host}:{port}...') ... return {'host': host, 'port': port} >>> db() connecting to SQL server at localhost:5432... {'host': 'localhost', 'port': 5432} >>> db() {'host': 'localhost', 'port': 5432}
See also
-
sidekick.functions.
call_after
[source]¶ Creates a function that invokes func once it’s called more than n times.
Parameters: - n – Number of times before starting invoking n.
- func – Function to be invoked.
- default – Value returned before func() starts being called.
Example
>>> f = sk.call_after(2, (X * 2), default=0) >>> [f(1), f(2), f(3), f(4), ...] [0, 0, 6, 8, ...]
See also
-
sidekick.functions.
call_at_most
[source]¶ Creates a function that invokes func while it’s called less than n times. Subsequent calls to the created function return the result of the last func invocation.
Parameters: - n – The number of calls at which func is no longer invoked.
- func – Function to restrict.
Examples
>>> log = sk.call_at_most(2, print) >>> log("error1"); log("error2"); log("error3"); log("error4") error1 error2
See also
-
sidekick.functions.
throttle
[source]¶ Limit the rate of execution of func to once at each
dt
seconds.When rate-limited, returns the last result returned by func.
Example
>>> f = sk.throttle(1, (X * 2)) >>> [f(21), f(14), f(7), f(0)] [42, 42, 42, 42]
-
sidekick.functions.
background
[source]¶ Return a function that executes in the background.
The transformed function return a thunk that forces the evaluation of the function in a blocking manner. Function can also be used as a decorator.
Parameters: - func – Function or callable wrapped to support being called in the background.
- timeout – Timeout in seconds.
- default – Default value to return if if function timeout when evaluation is requested, otherwise, raises a TimeoutError.
Examples
>>> fib = lambda n: 1 if n <= 2 else fib(n - 1) + fib(n - 2) >>> fib_bg = sk.background(fib, timeout=1.0) >>> result = fib_bg(10) # Do not block execution, return a thunk >>> result() # Call the result to get value (blocking operation) 55
-
sidekick.functions.
error
[source]¶ Raises the given exception.
If argument is not an exception, raises ValueError(exc).
Examples
>>> sk.error('some error') Traceback (most recent call last): ... ValueError: some error
See also
raising()
: create a function that raises an error instead of raising it immediately
-
sidekick.functions.
raising
[source]¶ Creates function that raises the given exception.
If argument is not an exception, raises ValueError(exc). The returning function accepts any number of arguments.
Examples
>>> func = sk.raising('some error') >>> func() Traceback (most recent call last): ... ValueError: some error
See also
raising()
: create a function that raises an error instead of raising it immediately
-
sidekick.functions.
retry
[source]¶ Retry to execute function at least n times before raising an error.
This is useful for functions that may fail due to interaction with external resources (e.g., fetch data from the network).
Parameters: - n – Maximum number of times to execute function
- func – Function that may raise errors.
- error – Exception or tuple with suppressed exceptions.
- sleep – Interval in which it sleeps between attempts.
Example
>>> queue = [111, 7, None, None] >>> process = sk.retry(5, lambda n: queue.pop() * n) >>> process(6) 42
-
sidekick.functions.
catch
[source]¶ Handle exception in function. If the exception occurs, it executes the given handler.
Examples
>>> nan = sk.always(float('nan')) >>> div = sk.catch(ZeroDivisionError, (X / Y), handler=nan) >>> div(1, 0) nan
The function can be used to re-write exceptions by passing the optional raises parameter.
>>> @sk.catch(KeyError, raises=ValueError("invalid name")) ... def get_value(name): ... return data[name]
-
sidekick.functions.
flip
[source]¶ Flip the order of arguments in a binary operator.
The resulting function is always curried.
Examples
>>> from operator import sub >>> rsub = sk.flip(sub) >>> rsub(2, 10) 8
-
sidekick.functions.
select_args
[source]¶ Creates a function that calls func with the arguments reordered.
Examples
>>> double = sk.select_args([0, 0], (X + Y)) >>> double(21) 42
-
sidekick.functions.
keep_args
[source]¶ Uses only the first n positional arguments to call func.
Examples
>>> incr = sk.keep_args(1, (X + 1)) >>> incr(41, 'whatever') 42
-
sidekick.functions.
reverse_args
[source]¶ Creates a function that invokes func with the positional arguments order reversed.
Examples
>>> concat = sk.reverse_args(lambda x, y, z: x + y + z) >>> concat("a", "b", "c") 'cba'
-
sidekick.functions.
skip_args
[source]¶ Skips the first n positional arguments before calling func.
Examples
>>> incr = sk.skip_args(1, (X + 1)) >>> incr('whatever', 41) 42
-
sidekick.functions.
splice_args
[source]¶ Return a function that receives a sequence as single argument and splice them into func.
Parameters: - func – Function that receives several positional arguments.
- slice – If given and is a slice, correspond to the slice in the input arguments that will be passed to func.
Example
>>> vsum = sk.splice_args(max) >>> vsum([1, 2, 3, 4]) 4