Function Object#
This module provides FunctionObject
,
a wrapper to extend functions with methods and operator overloads,
and can be called just like normal Python functions.
Yet they support numerous additional operators for function calling.
Conceptually, function objects are objects that implement the function call operator.
Usage#
Tip
Use FunctionObject
in interactive environments.
FunctionObject
s are particularly useful in interactive environments.
Instead of wrapping a large expression in another level of parentheses,
you can use application operators provided by FunctionObject
to apply the function on the following expression.
Writing f(...)
as f@(...)
seems redundant,
but these @
usages can be purged easily with simple search and replace.
FunctionObject
's operators are carefully chosen, as they:
- are relatively rare in Python
- have different precedence and associativity
This is especially useful when you wrap some debugging or logging code around a function call.
For example, with the following usage with icecream
,
you can replace ic @
with empty string to remove all debugging code,
without worrying of breaking the get_pic()
call:
from icecream import ic as _ic
ic = func(_ic)
result = ic @ (
get_pic(iris)
.filter(...)
.sort_values(...)
.apply(...)
.head(10)
)
|
and @
have different operator precedence,
the |
has almost the lowest precedence of all Python operators, while the @
has almost the highest precedence.
This allows you combine expressions more flexibly without worrying about parentheses.
&
operator can be used to apply the function to its left-hand side,
if the left-hand side does not overload the &
operator.
This is similar to &
, |>
or roughly %>%
.
**
operator has the highest precedence of all, and it has a unique
associtivity from right to left.
It can be used in wrapping multiple calls together without parentheses, like f(g(x))
can be written as f ** g ** x
.
It roughly simulates $
.
%
operator is used for calling multi-argument functions.
Tip
Do not use FunctionObject
s in library or main code base.
Only use them in scripts, notebooks or REPLs.
Function objects come with runtime costs.
Albeit negligible most of the time, the cost could accumulate on critical paths.
FunctionObject
s also have less static typing support.
Do not use them in type-checked code.
Warning
Wrapping callables with FunctionObject
will lose fields and methods of the original callable.
Be cautious especially when wrapping other callable objects.
Warning
For performance considerations, the majority of apfel
APIs are not wrapped in FunctionObject
s.
Classes#
FunctionObject
#
|#
Function application operator |
for FunctionObject
s.
f | x
is equivalent to f(x)
. This operator behaves the same as @
, but with a different precedence.
@#
Function application operator @
for FunctionObject
s.
f @ x
is equivalent to f(x)
. This operator behaves the same as |
, but with a different precedence.
&#
&
for FunctionObject
s.
This operator overloading targets the right-hand side.
x & f
is equivalent to f(x)
, if &
operator (left, __and__
) is not overloaded by x
's type.
Warning
np.array
and array-like types are common overloaders of &
, therefore this operator cannot be used with them.
**#
Function application operator **
for FunctionObject
s.
f ** g ** x
is equivalent to f(g(x))
.
This operator has the highest precedence of all overloadable operators,
and it binds from right to left.
It intends to simulate $
operator, except the precedence.
%#
Function application operator %
for FunctionObject
s of multi-argument functions.
- If the right hand side is a Sequence, spreads the sequence as positional arguments. For example,
x % (a, b, c)
is equivalent tox(a, b, c)
. - If the right hand side is a Mapping, spreads the mapping as keyword arguments. For example,
x % { "a": 1, "b": 2, "c": 3 }
is equivalent tox(a=1, b=2, c=3)
. - Specifically, you can use
...
as the map key to pass keyword arguments with keyword arguments at the same time,x % { ...: (1, 2), "c": 3 }
is equivalent tox(1, 2, c=3)
. - Otherwise, it calls on the right-hand side. This catches the case where you forget the trailing comma in the right-hand side tuple.
Example
Warning
This operator does not support the case where ...
(the Ellipsis
, not "..."
) is used as a keyword argument.
However, this case is relatively rare, as ...
cannot be declared as argument name.
Functions#
func
#
Turn callables into FunctionObject
yet keeps their original type hints.
Example
Note
As a callable, FunctionObject
has less static typing support.
@func
erases type hints of FunctionObject
while keeping the runtime type.
If you want to retain the type hints, directly use FunctionObject
's
constructor, or use reveal_func
on an object with runtime type FunctionObject
.