A comprehensive Python utility library for functional programming inspired by JavaScript's Lo-Dash
—
The Functions module provides 30 functions for higher-order function manipulation and utilities. These functions enable function composition, partial application, argument transformation, and execution control patterns common in functional programming.
def flow(*funcs: Callable) -> CallableCreates a function that is the composition of the provided functions, where each successive invocation is supplied the return value of the previous.
Parameters:
funcs (*Callable): Functions to compose.Returns:
Callable: New composite function.Example:
from pydash import flow
add = lambda x, y: x + y
square = lambda x: x ** 2
add_square = flow(add, square)
add_square(1, 2) # square(add(1, 2)) = square(3) = 9def flow_right(*funcs: Callable) -> CallableLike flow except that it creates a function composition where arguments are applied from right to left.
Parameters:
funcs (*Callable): Functions to compose.Returns:
Callable: New composite function.Example:
from pydash import flow_right
add = lambda x, y: x + y
square = lambda x: x ** 2
square_add = flow_right(add, square)
square_add(1, 2) # add(square(1), 2) = add(1, 2) = 3def over_args(func: Callable, *transforms: Callable) -> CallableCreates a function that invokes func with its arguments transformed by the corresponding transforms.
Parameters:
func (Callable): Function to wrap.transforms (*Callable): Argument transforms.Returns:
Callable: New function.Example:
from pydash import over_args
def greet(greeting, name):
return f"{greeting} {name}"
say_hello = over_args(greet, str.upper, str.capitalize)
say_hello('hello', 'world')
# 'HELLO World'def ary(func: Callable, n: int = None) -> CallableCreates a function that invokes func with up to n arguments, ignoring any additional arguments.
Parameters:
func (Callable): Function to cap arguments for.n (int, optional): Arity cap.Returns:
Callable: New capped function.Example:
from pydash import ary
def add_three(a, b, c):
return a + b + c
add_two = ary(add_three, 2)
add_two(1, 2, 3, 4, 5) # Only uses first 2 args: 1 + 2 + undefined = 3def unary(func: Callable) -> CallableCreates a function that accepts up to one argument, ignoring any additional arguments.
Parameters:
func (Callable): Function to cap arguments for.Returns:
Callable: New capped function.Example:
from pydash import unary
# Useful with map when you only want the first argument
numbers = ['1', '2', '3']
list(map(unary(int), numbers)) # [1, 2, 3]
# Without unary, int would receive index as second argumentdef negate(predicate: Callable) -> CallableCreates a function that negates the result of the predicate func.
Parameters:
predicate (Callable): Predicate to negate.Returns:
Callable: New negated function.Example:
from pydash import negate
is_even = lambda x: x % 2 == 0
is_odd = negate(is_even)
is_odd(3) # True
is_odd(4) # Falsedef rearg(func: Callable, *indexes: int) -> CallableCreates a function that invokes func with arguments arranged according to the specified indexes.
Parameters:
func (Callable): Function to rearrange arguments for.indexes (*int): Arranged argument indexes.Returns:
Callable: New function.Example:
from pydash import rearg
def greet(greeting, fname, lname):
return f"{greeting} {fname} {lname}"
say_hello = rearg(greet, 1, 2, 0)
say_hello('hello', 'john', 'doe')
# 'john doe hello'def after(n: int, func: Callable) -> CallableCreates a function that invokes func once it's called n or more times.
Parameters:
n (int): Number of calls before func is invoked.func (Callable): Function to restrict.Returns:
Callable: New restricted function.Example:
from pydash import after
saves = ['profile', 'settings']
done = after(len(saves), lambda: print('done saving!'))
# Call done for each save operation
for save in saves:
print(f'saving {save}')
done() # Only prints 'done saving!' after all callsdef before(n: int, func: Callable) -> CallableCreates a function that invokes func while it's called less than n times.
Parameters:
n (int): Number of calls at which func is no longer invoked.func (Callable): Function to restrict.Returns:
Callable: New restricted function.Example:
from pydash import before
add_one = lambda x: x + 1
add_one_twice = before(3, add_one)
add_one_twice(1) # 2
add_one_twice(1) # 2
add_one_twice(1) # 2 (function not called, returns last result)def once(func: Callable) -> CallableCreates a function that is restricted to invoking func once. Repeat calls to the function return the value of the first invocation.
Parameters:
func (Callable): Function to restrict.Returns:
Callable: New restricted function.Example:
from pydash import once
initialize = once(lambda: print('Initialized!'))
initialize() # 'Initialized!'
initialize() # (no output, returns cached result)def debounce(func: Callable, wait: int, immediate: bool = False) -> CallableCreates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked.
Parameters:
func (Callable): Function to debounce.wait (int): Milliseconds to delay.immediate (bool): Specify invoking on the leading edge of timeout. Defaults to False.Returns:
Callable: New debounced function.Example:
from pydash import debounce
import time
# Debounce expensive operation
save_input = debounce(lambda x: print(f'Saving: {x}'), 1000)
save_input('a')
save_input('ab')
save_input('abc') # Only this call will execute after 1 second delaydef throttle(func: Callable, wait: int) -> CallableCreates a throttled function that only invokes func at most once per every wait milliseconds.
Parameters:
func (Callable): Function to throttle.wait (int): Milliseconds to throttle invocations to.Returns:
Callable: New throttled function.Example:
from pydash import throttle
# Throttle scroll handler
handle_scroll = throttle(lambda: print('Scrolling!'), 100)
# Even if called rapidly, only executes every 100ms
for i in range(10):
handle_scroll()def curry(func: Callable, arity: int = None) -> CallableCreates a curried version of func which accepts arguments of func and either invokes func returning its result, if at least arity number of arguments have been provided, or returns a function that accepts the remaining arguments.
Parameters:
func (Callable): Function to curry.arity (int, optional): Arity of func.Returns:
Callable: New curried function.Example:
from pydash import curry
def add_three(a, b, c):
return a + b + c
curried_add = curry(add_three)
# Can be called multiple ways:
curried_add(1)(2)(3) # 6
curried_add(1, 2)(3) # 6
curried_add(1)(2, 3) # 6
curried_add(1, 2, 3) # 6def curry_right(func: Callable, arity: int = None) -> CallableLike curry except that arguments are applied to func in the manner of partial_right instead of partial.
Parameters:
func (Callable): Function to curry.arity (int, optional): Arity of func.Returns:
Callable: New curried function.Example:
from pydash import curry_right
def divide(a, b):
return a / b
divide_by = curry_right(divide)
divide_by_2 = divide_by(2)
divide_by_2(10) # 10 / 2 = 5def partial(func: Callable, *args: Any, **kwargs: Any) -> CallableCreates a function that invokes func with args prepended to the arguments it receives.
Parameters:
func (Callable): Function to partially apply arguments to.args (*Any): Arguments to prepend.kwargs (**Any): Keyword arguments to prepend.Returns:
Callable: New partially applied function.Example:
from pydash import partial
def greet(greeting, name):
return f"{greeting} {name}!"
say_hello = partial(greet, 'Hello')
say_hello('World') # 'Hello World!'
say_hi = partial(greet, greeting='Hi')
say_hi('Python') # 'Hi Python!'def partial_right(func: Callable, *args: Any) -> CallableLike partial except that arguments are appended to those provided to the new function.
Parameters:
func (Callable): Function to partially apply arguments to.args (*Any): Arguments to append.Returns:
Callable: New partially applied function.Example:
from pydash import partial_right
def greet(greeting, name):
return f"{greeting} {name}!"
greet_world = partial_right(greet, 'World')
greet_world('Hello') # 'Hello World!'def conjoin(*predicates: Callable) -> CallableCreates a function that is the logical AND of the provided predicates.
Parameters:
predicates (*Callable): Predicates to check.Returns:
Callable: New conjoined function.Example:
from pydash import conjoin
is_positive = lambda x: x > 0
is_even = lambda x: x % 2 == 0
is_positive_even = conjoin(is_positive, is_even)
is_positive_even(4) # True (positive AND even)
is_positive_even(-2) # False (not positive)
is_positive_even(3) # False (not even)def disjoin(*predicates: Callable) -> CallableCreates a function that is the logical OR of the provided predicates.
Parameters:
predicates (*Callable): Predicates to check.Returns:
Callable: New disjoined function.Example:
from pydash import disjoin
is_string = lambda x: isinstance(x, str)
is_number = lambda x: isinstance(x, (int, float))
is_string_or_number = disjoin(is_string, is_number)
is_string_or_number('hello') # True
is_string_or_number(42) # True
is_string_or_number([]) # Falsedef flip(func: Callable) -> CallableCreates a function that invokes func with arguments reversed.
Parameters:
func (Callable): Function to flip arguments for.Returns:
Callable: New flipped function.Example:
from pydash import flip
def divide(a, b):
return a / b
flipped_divide = flip(divide)
flipped_divide(2, 10) # 10 / 2 = 5def spread(func: Callable) -> CallableCreates a function that invokes func with the array argument spread as individual arguments.
Parameters:
func (Callable): Function to spread arguments for.Returns:
Callable: New function.Example:
from pydash import spread
def add_three(a, b, c):
return a + b + c
spread_add = spread(add_three)
spread_add([1, 2, 3]) # 6def wrap(value: Any, wrapper: Callable) -> CallableCreates a function that provides value to wrapper as its first argument. Additional arguments provided to the function are appended to those provided to the wrapper.
Parameters:
value (Any): Value to wrap.wrapper (Callable): Wrapper function.Returns:
Callable: New wrapped function.Example:
from pydash import wrap
greet = lambda name: f"Hello {name}!"
wrapped_greet = wrap(greet, lambda func, name: func(name).upper())
wrapped_greet('world') # 'HELLO WORLD!'def delay(func: Callable, wait: int, *args: Any, **kwargs: Any) -> AnyInvokes func after wait milliseconds. Any additional arguments are provided to func when it's invoked.
Parameters:
func (Callable): Function to delay.wait (int): Milliseconds to delay invocation.args (*Any): Arguments to invoke func with.kwargs (**Any): Keyword arguments to invoke func with.Returns:
Any: Timer object that can be used to cancel the delayed invocation.Example:
from pydash import delay
def say_hello(name):
print(f'Hello {name}!')
# Delay execution by 1000ms
timer = delay(say_hello, 1000, 'World')def iterated(func: Callable, n: int) -> CallableCreates a function that applies func n times to its argument.
Parameters:
func (Callable): Function to iterate.n (int): Number of times to iterate function.Returns:
Callable: New iterated function.Example:
from pydash import iterated
add_one = lambda x: x + 1
add_five = iterated(add_one, 5)
add_five(0) # 5 (adds 1 five times)def juxtapose(*funcs: Callable) -> CallableCreates a function whose return value is a list of the results of calling each provided function with the supplied arguments.
Parameters:
funcs (*Callable): Functions to juxtapose.Returns:
Callable: New juxtaposed function.Example:
from pydash import juxtapose
def add_one(x):
return x + 1
def multiply_two(x):
return x * 2
def square(x):
return x ** 2
multi_math = juxtapose(add_one, multiply_two, square)
multi_math(3) # [4, 6, 9]from pydash import flow, partial
# Data processing pipeline
def clean_data(data):
return [x.strip().lower() for x in data if x.strip()]
def validate_data(data):
return [x for x in data if len(x) > 2]
def transform_data(data):
return [x.title() for x in data]
# Create processing pipeline
process_data = flow(clean_data, validate_data, transform_data)
raw_data = [' hello ', '', 'WORLD', ' hi ', 'bye']
result = process_data(raw_data) # ['Hello', 'World']from pydash import debounce, throttle, once
# Debounced search (wait for user to stop typing)
def perform_search(query):
print(f"Searching for: {query}")
debounced_search = debounce(perform_search, 300)
# Throttled scroll handler (limit execution rate)
def update_scroll_position():
print("Updating scroll position")
throttled_scroll = throttle(update_scroll_position, 16) # ~60fps
# One-time initialization
def initialize_app():
print("App initialized!")
init_once = once(initialize_app)from pydash import curry, partial, partial_right
# Curried logging function
@curry
def log_message(level, category, message):
return f"[{level}] {category}: {message}"
# Create specialized loggers
error_log = log_message('ERROR')
warn_db = log_message('WARN', 'DATABASE')
# Use them
error_log('AUTH', 'Invalid token') # [ERROR] AUTH: Invalid token
warn_db('Connection timeout') # [WARN] DATABASE: Connection timeout
# Partial application for API configuration
def api_request(method, endpoint, data=None, headers=None):
return f"{method} {endpoint} with {data} and {headers}"
# Create specialized request functions
get_request = partial(api_request, 'GET')
post_user = partial_right(api_request, headers={'Content-Type': 'application/json'})from pydash import conjoin, disjoin, negate
# Define basic predicates
is_adult = lambda person: person.get('age', 0) >= 18
is_verified = lambda person: person.get('verified', False)
is_premium = lambda person: person.get('premium', False)
# Compose complex predicates
can_access_content = conjoin(is_adult, is_verified)
has_special_access = disjoin(is_premium, conjoin(is_adult, is_verified))
is_restricted = negate(can_access_content)
# Use composed predicates
user = {'age': 25, 'verified': True, 'premium': False}
can_access_content(user) # True
has_special_access(user) # True
is_restricted(user) # FalseThis Functions module provides comprehensive higher-order function utilities with 24 functions enabling sophisticated functional programming patterns including composition, partial application, execution control, and function transformation.
Install with Tessl CLI
npx tessl i tessl/pypi-pydash