Backport of the functools module from Python 3.2.3 for use on 2.7 and PyPy.
npx @tessl/cli install tessl/pypi-functools32@3.2.0A backport of the functools module from Python 3.2.3 for use on Python 2.7 and PyPy. This package brings modern functional programming utilities and caching decorators to legacy Python environments, enabling cleaner functional programming patterns and performance optimizations.
pip install functools32import functools32For direct access to functions:
from functools32 import lru_cache, partial, wraps, total_orderingOrderedDict is also available (used internally by lru_cache):
from functools32 import OrderedDictImport all public functions:
from functools32 import *from functools32 import lru_cache, partial, wraps
# Use LRU cache decorator for memoization
@lru_cache(maxsize=128)
def expensive_function(n):
# Simulate expensive computation
result = sum(i * i for i in range(n))
return result
# Create partial functions
multiply_by_2 = partial(lambda x, y: x * y, 2)
result = multiply_by_2(5) # Returns 10
# Use wraps for decorators
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Calling {}".format(func.__name__))
return func(*args, **kwargs)
return wrapper
@my_decorator
def greet(name):
return "Hello, {}!".format(name)Essential decorators and utilities for function wrapping, caching, and metadata preservation.
def lru_cache(maxsize=100):
"""
Least-recently-used cache decorator.
Parameters:
- maxsize (int, optional): Maximum cache size. Default 100. Set to None for unbounded cache.
Returns:
Decorator function that adds caching to the wrapped function.
The decorated function gets these additional methods:
- cache_info(): Returns CacheInfo namedtuple with hits, misses, maxsize, currsize
- cache_clear(): Clears the cache and statistics
"""
def wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES):
"""
Decorator factory to apply update_wrapper() to a wrapper function.
Parameters:
- wrapped: Original function to wrap
- assigned (tuple, optional): Attributes to assign directly from wrapped to wrapper
- updated (tuple, optional): Attributes to update with corresponding wrapper attributes
Returns:
Decorator function that applies update_wrapper() with specified arguments
"""
def update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES):
"""
Update a wrapper function to look like the wrapped function.
Parameters:
- wrapper: Function to be updated
- wrapped: Original function
- assigned (tuple, optional): Attributes assigned directly from wrapped to wrapper
- updated (tuple, optional): Attributes of wrapper updated with wrapped function attributes
Returns:
Updated wrapper function
"""Class-level decorators for enhanced functionality and automatic method generation.
def total_ordering(cls):
"""
Class decorator that fills in missing ordering methods.
Given a class which defines one or more rich comparison ordering methods,
this class decorator supplies the rest.
Parameters:
- cls: Class to decorate
Returns:
Class with completed ordering methods (__lt__, __le__, __gt__, __ge__)
Requirements:
The class must define at least one ordering operation: < > <= >=
"""Core functional programming functions for partial application, reduction, and comparison utilities.
def partial(func, *args, **keywords):
"""
Return a new partial object which when called will behave like func called with
the positional arguments args and keyword arguments keywords.
Parameters:
- func: Function to create partial application for
- *args: Positional arguments to pre-fill
- **keywords: Keyword arguments to pre-fill
Returns:
Partial object with callable interface
"""
def reduce(function, sequence, initial=None):
"""
Apply a function of two arguments cumulatively to the items of sequence,
from left to right, so as to reduce the sequence to a single value.
Parameters:
- function: Function of two arguments
- sequence: Iterable sequence to reduce
- initial (optional): Starting value; if not provided, first sequence item is used
Returns:
Reduced result value
"""
def cmp_to_key(mycmp):
"""
Convert a cmp= function into a key= function for sorting.
Parameters:
- mycmp: Comparison function that returns negative, zero, or positive value
Returns:
Key function suitable for sorting operations (sorted(), list.sort(), etc.)
"""Ordered dictionary implementation that maintains insertion order while providing standard dictionary operations.
class OrderedDict(dict):
"""
Dictionary that remembers insertion order.
Inherits from dict and maintains insertion order of keys while providing
all standard dictionary operations with order-aware behavior.
"""
def __init__(self, *args, **kwds):
"""
Initialize an ordered dictionary.
Parameters:
- *args: Same as dict() constructor
- **kwds: Keyword arguments (insertion order not guaranteed)
"""
def popitem(self, last=True):
"""
Remove and return a (key, value) pair.
Parameters:
- last (bool, optional): If True (default), return in LIFO order.
If False, return in FIFO order.
Returns:
tuple: (key, value) pair
Raises:
KeyError: If dictionary is empty
"""
def move_to_end(self, key, last=True):
"""
Move an existing element to the end (or beginning if last==False).
Parameters:
- key: Existing key to move
- last (bool, optional): If True (default), move to end.
If False, move to beginning.
Raises:
KeyError: If key does not exist
"""
def clear(self):
"""
Remove all items from the ordered dictionary.
"""
def pop(self, key, default=None):
"""
Remove specified key and return the corresponding value.
Parameters:
- key: Key to remove
- default (optional): Value to return if key is not found. If not provided
and key doesn't exist, KeyError is raised.
Returns:
Value associated with key, or default if key not found and default provided
Raises:
KeyError: If key is not found and no default is provided
"""
def setdefault(self, key, default=None):
"""
Get the value of key, or set and return default if key doesn't exist.
Parameters:
- key: Key to get or set
- default (optional): Default value to set and return if key doesn't exist
Returns:
Value associated with key or the default value
"""
def copy(self):
"""
Create a shallow copy of the ordered dictionary.
Returns:
OrderedDict: Shallow copy with same key order
"""
@classmethod
def fromkeys(cls, iterable, value=None):
"""
Create a new ordered dictionary with keys from iterable.
Parameters:
- iterable: Keys for the new dictionary
- value (optional): Value for all keys. Defaults to None.
Returns:
OrderedDict: New ordered dictionary
"""Pre-defined constants for wrapper function metadata handling.
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
# Tuple of attributes assigned directly from wrapped to wrapper function
WRAPPER_UPDATES = ('__dict__',)
# Tuple of attributes updated from wrapped to wrapper functionfrom collections import namedtuple
CacheInfo = namedtuple("CacheInfo", "hits misses maxsize currsize")
# Named tuple returned by lru_cache.cache_info() containing cache statistics.
# Fields:
# - hits (int): Number of cache hits
# - misses (int): Number of cache misses
# - maxsize (int): Maximum cache size (None if unbounded)
# - currsize (int): Current cache sizefrom functools32 import lru_cache
@lru_cache(maxsize=256)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# Check cache statistics
print(fibonacci.cache_info()) # CacheInfo(hits=0, misses=0, maxsize=256, currsize=0)
# Use the function
result = fibonacci(100)
# Check updated statistics
print(fibonacci.cache_info()) # Shows hits, misses, and current size
# Clear cache
fibonacci.cache_clear()from functools32 import total_ordering
@total_ordering
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def __eq__(self, other):
return self.grade == other.grade
def __lt__(self, other):
return self.grade < other.grade
# Now all comparison operations work
student1 = Student("Alice", 85)
student2 = Student("Bob", 92)
print(student1 < student2) # True
print(student1 <= student2) # True
print(student1 > student2) # False
print(student1 >= student2) # Falsefrom functools32 import OrderedDict
# Create ordered dictionary
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# Move element to end
od.move_to_end('a')
print(list(od.keys())) # ['b', 'c', 'a']
# Pop items in order
last_item = od.popitem() # ('a', 1)
first_item = od.popitem(last=False) # ('b', 2)
# Create from keys with default value
od2 = OrderedDict.fromkeys(['x', 'y', 'z'], 0)
print(od2) # OrderedDict([('x', 0), ('y', 0), ('z', 0)])
# Use setdefault to get or set values
od3 = OrderedDict([('a', 1), ('b', 2)])
value = od3.setdefault('c', 3) # Adds 'c': 3, returns 3
existing = od3.setdefault('a', 99) # Returns 1, doesn't change 'a'
# Pop with default value
popped = od3.pop('d', 'not found') # Returns 'not found'
popped = od3.pop('c') # Returns 3, removes 'c'
# Clear all items
od3.clear() # Now emptyfrom functools32 import wraps
import time
def timing_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print("{} took {:.4f} seconds".format(func.__name__, end - start))
return result
return wrapper
@timing_decorator
def slow_function():
"""A function that takes some time to execute."""
time.sleep(1)
return "Done"
# The wrapper preserves the original function's metadata
print(slow_function.__name__) # 'slow_function'
print(slow_function.__doc__) # 'A function that takes some time to execute.'