Module better_functools.apply

Functions

def static(fn: Callable[Concatenate[T, P], R]) ‑> Callable[~P, apply[Callable[[~T], ~R]]]
Expand source code
def static(fn: Callable[Concatenate[T, P], R]) -> Callable[P, apply[Callable[[T], R]]]:
    """*Experimental*: Make a bound method static.

    This makes it easier to chain the method.

    suppose you have a bound method on an object of type `MyType`
    ```
    obj.method: (*args, **kwargs) -> ReturnType
    ```
    Applying static:
    ```
    static(MyType.method): (*args, **kwargs) -> ((MyType) -> ReturnType)
    ```

    Example:
    >>> get_id = static(dict[str, int].__getitem__)("id")
    >>> get_id({"id": 1234})
    1234

    Limitations:
    - Generics on the parent class maybe lost explicitly specify the generic type in such cases.
    - Does not work well with MyPy.
    """

    def _outer(*args: P.args, **kwargs: P.kwargs) -> apply[Callable[[T], R]]:
        @apply
        def _inner(first: T) -> R:
            return fn(first, *args, **kwargs)

        return _inner

    return _outer

Experimental: Make a bound method static.

This makes it easier to chain the method.

suppose you have a bound method on an object of type MyType

obj.method: (*args, **kwargs) -> ReturnType

Applying static:

static(MyType.method): (*args, **kwargs) -> ((MyType) -> ReturnType)

Example:

>>> get_id = static(dict[str, int].__getitem__)("id")
>>> get_id({"id": 1234})
1234

Limitations: - Generics on the parent class maybe lost explicitly specify the generic type in such cases. - Does not work well with MyPy.

Classes

class apply (fn: T_APPLY)
Expand source code
class apply(Generic[T_APPLY]):
    """Make a function callable by using `@` operator.

    This is the `@` version of `... | fn` in `more_functools.pipe.Composition`.

    >>> "1234" @ apply(int)
    1234
    """

    def __init__(self, fn: T_APPLY) -> None:
        self.fn = fn

    if TYPE_CHECKING:
        __call__: T_APPLY
        __rmatmul__: T_APPLY
    else:

        def __call__(self, *args, **kwargs):
            return self.fn(*args, **kwargs)

        __rmatmul__ = __call__

Make a function callable by using @ operator.

This is the @ version of ... | fn in more_functools.pipe.Composition.

>>> "1234" @ apply(int)
1234

Ancestors

  • typing.Generic
class bind (val: T)
Expand source code
@dataclass
class bind(Generic[T]):
    """Bind the first argument to the function.

    >>> def add(x: int, y: int) -> int:
    ...     return x + y
    >>> (add @ bind(2))(5)
    7
    """

    val: T

    def __call__(self, fn: Callable[Concatenate[T, P], R]) -> Callable[P, R]:
        def _new_fn(*args: P.args, **kwargs: P.kwargs) -> R:
            return fn(self.val, *args, **kwargs)

        return _new_fn

    def __rmatmul__(self, fn: Callable[Concatenate[T, P], R]) -> Callable[P, R]:
        return self(fn)

Bind the first argument to the function.

>>> def add(x: int, y: int) -> int:
...     return x + y
>>> (add @ bind(2))(5)
7

Ancestors

  • typing.Generic

Class variables

var val : ~T
class compose (fn: Callable[[T], R])
Expand source code
@dataclass
class compose(Generic[T, R]):
    """Compose functions.

    This is similar to `more_functools.pipe.Composition`,
    but allows it to be done with `@`.

    >>> def add(x: int, y: int) -> int:
    ...     return x + y
    >>> add_plus_one = add @ compose(add @ bind(1))
    >>> add_plus_one(2, 3)
    6
    """

    fn: Callable[[T], R]

    def __call__(self, other: Callable[P, T]) -> Callable[P, R]:
        def _call(*args: P.args, **kwargs: P.kwargs) -> R:
            return self.fn(other(*args, **kwargs))

        return _call

    __rmatmul__ = __call__

Compose functions.

This is similar to more_functools.pipe.Composition, but allows it to be done with @.

>>> def add(x: int, y: int) -> int:
...     return x + y
>>> add_plus_one = add @ compose(add @ bind(1))
>>> add_plus_one(2, 3)
6

Ancestors

  • typing.Generic

Class variables

var fn : Callable[[~T], ~R]
class invoke (*args: Unpack[Ts])
Expand source code
class invoke(Generic[Unpack[Ts]]):
    """Invoke a function with the given positional args.

    This is useful when dealing with a `@` chain.

    >>> def add(x: int, y: int, z: int) -> int:
    ...     return x + y + z
    >>> (add @ bind(1) @ bind(2))(3)  # hard to read
    6
    >>> add @ bind(1) @ bind(2) @ invoke(3)
    6
    """

    def __init__(self, *args: Unpack[Ts]) -> None:
        self.args = args

    def __call__(self, fn: Callable[[Unpack[Ts]], R]) -> R:
        return fn(*self.args)

    __rmatmul__ = __call__

Invoke a function with the given positional args.

This is useful when dealing with a @ chain.

>>> def add(x: int, y: int, z: int) -> int:
...     return x + y + z
>>> (add @ bind(1) @ bind(2))(3)  # hard to read
6
>>> add @ bind(1) @ bind(2) @ invoke(3)
6

Ancestors

  • typing.Generic