from functools import lru_cache
from typing import Callable
__all__ = [
'efunc',
'Expression',
]
@lru_cache()
def _raw_expr_func():
return getattr(Expression, '_expr')
def _raw_expr(e) -> 'Expression':
return _raw_expr_func()(e)
[docs]def efunc(e) -> Callable:
"""
Overview:
Get callable object from any types.
:param e: Original object.
:return: Callable object. If given ``e`` is an :class:`Expression`, its callable method will be returned. \
If given ``e`` is a function, an equivalent method will be returned. Otherwise, a method which always return \
``e`` will be returned.
.. note::
This is the key feature of the native expressions, you need to use :func:`efunc` function to transform \
expressions to callable functions.
Examples::
>>> from hbutils.expression import keep, efunc, expr
>>>
>>> e1 = keep()
>>> efunc(e1 == 1)(1)
True
>>> efunc(e1 == 1)(2)
False
>>>
>>> e2 = expr(lambda x: x + 2)
>>> efunc(e2 == 1)(-1)
True
>>> efunc(e2 == 1)(1)
False
"""
return getattr(_raw_expr(e), '_fcall')
[docs]class Expression:
"""
Overview:
Base class of expressions.
"""
[docs] def __init__(self, func=None):
"""
Constructor of :class:`Expression`.
:param func: Callable function, default is ``None`` which means a ``lambda x: x`` will be used.
"""
self._fcall = func or (lambda x: x)
[docs] def _func(self, func: Callable, *args, **kwargs):
"""
Expression building based on given ``func`` and arguments.
:param func: Logical function.
:param args: Positional arguments.
:param kwargs: Key-word arguments.
:return: New expression with current class.
Examples::
>>> from hbutils.expression import efunc, Expression
>>>
>>> class MyExpression(Expression):
... def add(self, other):
... return self._func(lambda x, y: x + y, self, other)
...
>>>
>>> e1 = MyExpression()
>>> efunc(e1.add(1))(5) # 5 + 1 = 6
6
>>> efunc(e1.add(e1.add(1)))(5) # 5 + (5 + 1) = 11
11
"""
_args = tuple(efunc(v) for v in args)
_kwargs = {k: efunc(v) for k, v in kwargs.items()}
def _new_func(x):
return func(
*(v(x) for v in _args),
**{k: v(x) for k, v in _kwargs.items()},
)
return self.__class__(_new_func)
[docs] @classmethod
def _expr(cls, v):
"""
Build expression with this class.
:param v: Any types of value.
:return: An expression object.
"""
if isinstance(v, Expression):
return v
elif callable(v):
return cls(v)
else:
return cls(lambda x: v)