funcy

repository·master·Indexed 26 days ago

https://github.com/suor/funcy

A collection of practical functional programming tools for Python, inspired by Clojure and Underscore. It provides utilities for sequence manipulation, collection and dictionary operations, functional composition, and abstracting control flow. Key features include caching decorators like @memoize and @cache, nested collection access via get_in and set_in, and a wide range of transformation, filtering, and grouping helpers.

Tokens
15K
Snippets
45
Records
93
Agent score
86%

What's inside funcy

  1. Use extended function semantics in funcy

    master

    Many funcy functions that typically expect a callable (a function or predicate) can instead accept non-callable objects. When you pass these objects, funcy automatically applies specific semantics based on the type of the object provided:

    TypeMapping Function SemanticsPredicate Semantics
    Noneidentity(x)bool(x)
    stringre_finder(f)re_tester(f)
    int or sliceitemgetter(f)itemgetter(f)
    mappinglambda x: f[x]lambda x: f[x]
    setlambda x: x in flambda x: x in f
  2. Log function entry and exit with log_enters() and log_exits()

    master
    Use @log_enters(print_func, ...) or @log_exits(print_func, ...) to track only the start or the end of a function execution. These can be used as decorators or tapped into call expressions.
  3. Curry functions with curry(), rcurry(), and autocurry()

    master

    Currying transforms a function of multiple arguments into a series of functions that each take one argument.

    • curry(func[, n]): Standard currying (left-to-right).
    • rcurry(func[, n]): Reverse currying (right-to-left). Useful for fixing the first arguments by providing the last ones first.
    • autocurry(func): Automatically returns partial applications until all required arguments are provided.
  4. Convert iterators to lists with @collecting

    master

    The @collecting decorator transforms a generator or iterator-returning function into one that returns a list. This is useful for turning lazy properties into eager ones.

    @property
    @collecting
    def path_up(self):
        node = self
        while node:
            yield node
            node = node.parent
  5. Create real function objects with func_partial()

    master

    While partial() is faster, it returns a callable object. If you specifically need a real function object (for example, to attach it as a method using setattr), use func_partial(func, *args, **kwargs).

    setattr(self, 'get_%s_display' % field.name, func_partial(_get_FIELD_display, field))
  6. Select elements with select and compact

    master

    Use these functions to filter collections based on predicates or patterns.

    • select(predicate, coll): Returns elements that satisfy the predicate.
    • select_keys(predicate, dict): Returns dictionary entries where keys satisfy the predicate.
    • compact(coll): Removes falsy values (like None or 0) from a collection.
    from funcy import select, select_keys, compact
    
    select(even, {1,2,3,10,20})                  # {2,10,20}
    select(r'^a', ('a','b','ab','ba'))           # ('a','ab')
    select_keys(callable, {str: '', None: None}) # {str: ''}
    compact({2, None, 1, 0})                     # {1,2}
  7. Memoize function results with @memoize

    master

    Use the @memoize decorator to cache function results in memory, trading memory for improved performance.

    To prevent caching failed attempts (e.g., due to timeouts), you can raise memoize.skip(VALUE). This allows the function to return a value without storing it in the cache.

    You can also manually manipulate the cache memory using the .memory attribute on the decorated function.

    @memoize
    def ip_to_city(ip):
        try:
            return request_city_from_slow_service(ip)
        except NotFound:
            return None               # returns and memoizes None
        except Timeout:
            raise memoize.skip(CITY)  # returns CITY, but does NOT memoize it
    
    # Manipulate memory
    ip_to_city.memory.update({ip_val: city_val})
    ip_to_city.memory.clear()
    
    # Use custom key function for unhashable objects
    @memoize(key_func=lambda obj, verbose=None: obj.key)
    def do_things(obj, verbose=False):
        pass
  8. Transform dictionary keys or values

    master

    Use these functions to transform only the keys or only the values of a mapping (dict) or a collection of pairs:

    • walk_keys(f, coll): Maps function f over the keys. Preserves mapping types like dict, defaultdict, or OrderedDict.
    • walk_values(f, coll): Maps function f over the values.

    Note on defaultdict: walk_values handles defaultdict specially. The new defaultdict will have a default factory that is a composition of f and the original factory.

    walk_keys(str.upper, {'a': 1, 'b': 2}) # {'A': 1, 'B': 2}
    walk_values(int, form_values)
    # Special handling for defaultdict:
    d = defaultdict(lambda: 'default', a='hi', b='bye')
    walk_values(str.upper, d)
    # -> defaultdict(lambda: 'DEFAULT', a='HI', b='BYE')
  9. Create silent lookup functions with @silent_lookuper

    master
    The @silent_lookuper decorator behaves identically to @make_lookuper, except that instead of raising a LookupError when a key is missing from the memory, it returns None.