A script to chain multiple closures in python with example usage.

Closure chaining

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20

from functools import wraps


# A new closure will be returned as a chain of Closures in the incoming list order
def chain_closures(closure_list=None):
    if not closure_list:
        return None

    def chain(f):
        @wraps(f)
        def r(*args, **kwargs):
            newfunc = f
            for c in reversed(closure_list):
                newfunc = c(newfunc)
            return newfunc(*args, **kwargs)

        return r

    return chain

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

from functools import wraps
from closures import chain_closures
import logging

logger = logging.getLogger()

def x(a):
    def request_logger(f):
        @wraps(f)
        def rlog(*args, **kwargs):
            logger.info("%s x entry", a)
            ret = f(*args, **kwargs)
            logger.info("%s x exit", a)
            return ret

        return rlog

    return request_logger


def y(b):
    def request_logger(f):
        @wraps(f)
        def rlog(*args, **kwargs):
            logger.info("%s y entry", b)
            ret = f(*args, **kwargs)
            logger.info("%s y exit", b)
            return ret

        return rlog

    return request_logger


def z(a, b):
    c1 = x(a)
    c2 = y(b)

    def request_logger(f):
        @wraps(f)
        def rlog(*args, **kwargs):
            q = c1(c2(f))
            logger.info("z entry")
            ret = q(*args, **kwargs)
            logger.info("z exit")
            return ret

        return rlog

    return request_logger


def w(a, b, f):
    c1 = x(a)
    c2 = y(b)
    q = c1(c2(f))
    return q


def get_w(a, b):
    c1 = x(a)
    c2 = y(b)
    q = chain_closures([c1, c2])
    return q


def f1(a, b):
    logger.info("%s %s", a, b)
    # raise Exception("me except")


def smain():
    c4 = get_w(10, 11)
    f2 = c4(f1)
    f2(12, 13)
    logger.info(f2.__name__)


if __name__ == "__main__":
    logging.basicConfig(format='%(asctime)s - %(message)s', datefmt='%d-%b-%y %H:%M:%S', level=logging.DEBUG)
    smain()