Post-process generated values with a decorator.

Gribouillis 2 Tallied Votes 569 Views Share

This snippet defines a simple decorator to post-process a function's return value through a sequence of filters. As a first application, the decorator can transform a generator function into a function returning a sequence type (list, tuple, dict).

# python >= 2.6
from __future__ import print_function
from functools import update_wrapper

def post_process(*filters):
    """Decorator to post process a function's return value through a
    sequence of filters (functions with a single argument).
    
    Example:
        
        @post_process(f1, f2, f3)
        def f(*args, **kwd):
            ...
            return value
        
        then calling f(...) will actually return f3( f2( f1( f(...)))).
        
        This can also be used to convert a generator to a function
        returning a sequence type:
            
        @post_process(dict)
        def my_generator():
            ...
            yield key, value
            
    """
    
    def decorate(func):
        def wrapper(*args, **kwd):
            rv = func(*args, **kwd)
            for f in filters:
                rv = f(rv)
            return rv
        update_wrapper(wrapper, func)
        return wrapper
    return decorate


@post_process(dict)
def stones(n):
    while n > 1:
        x = (3 * n + 1) // 2 if n % 2 else n // 2
        yield n, x
        n = x

@post_process(list)
def fibo(n):
    a, b = 0, 1
    for i in range(n):
        yield a
        a, b = b, a + b

@post_process(list, reversed, list)
def squares(n):
    for i in range(n):
        yield i * i
        
if __name__ == "__main__":
    print("stones", stones(11))
    print("fibo", fibo(12))
    print("squares", squares(10))
    
""" my output -->
stones {2: 1, 4: 2, 5: 8, 8: 4, 10: 5, 11: 17, 13: 20, 17: 26, 20: 10, 26: 13}
fibo [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
squares [81, 64, 49, 36, 25, 16, 9, 4, 1, 0]
"""
Gribouillis 1,391 Programming Explorer Team Colleague

How to transform such a generator into a function returning a tuple of all items

from itertools import chain

@post_process(chain.from_iterable, tuple)
def runme():
    yield (1, 2)
    yield (i + 3 for i in range(4))
    yield [7, 8]

print(runme())

""" my output -->
(1, 2, 3, 4, 5, 6, 7, 8)
"""
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.