Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: to wrap functions via lambda

I have some code like

class EventHandler:
    def handle(self, event):
        pass

def wrap_handler(handler):
    def log_event(proc, e):
        print e
        proc(e)
    handler.handle = lambda e: log_event(handler.handle, e)

handler = EventHandler()
wrap_handler(handler)
handler.handle('event')

that will end up with infinite recursion. While changing wrap_handler to

def wrap_handler(handler):
    def log_event(proc, e):
        print e
        proc(e)
    # handler.handle = lambda e: log_event(handler.handle, e)
    handle_func = handler.handle
    handler.handle = lambda e: log_event(handle_func, e)

the program will become OK. Why is that? And could anyone tell me more common ways to wrap functions?

like image 999
neuront Avatar asked Apr 13 '26 23:04

neuront


2 Answers

It ends in an infinite recursion as when lambda e: log_event(handler.handle, e) is called, handler.handle is already the lambda expression. log_event would call the lambda and the lambda would call log_event, etc..

To fix this, just save the current method in the local-scope, this also does not need the additional lambda-expression.

class EventHandler:
    def handle(self, event):
        pass

def wrap_handler(handler):
    proc = handler.handle
    def log_event(e):
        print e
        proc(e)
    handler.handle = log_event

handler = EventHandler()
wrap_handler(handler)
handler.handle('event')

You could also use a decorator.

def logging(function):
    def wrapper(*args, **kwargs):
        print "Calling %s with:" % function.__name__, args, kwargs
        return function(*args, **kwargs)
    return wrapper

class EventHandler:
    @ logging
    def handle(self, event):
        pass

    def __repr__(self):
        return "EventHandler instance"

handler = EventHandler()
handler.handle('event')

C:\Users\niklas\Desktop>foo.py
Calling handle with: (EventHandler instance, 'event') {}

like image 142
Niklas R Avatar answered Apr 16 '26 12:04

Niklas R


handler.handle = lambda e: log_event(handler.handle, e)

The anonymous function will, upon invocation, look up handler's handle member and pass that (along with e) to log_event. Because you immediately set handler.handle to the anonymous function, the anonymous function just gets a reference to itself.

This on the other hand:

handle_func = handler.handle
handler.handle = lambda e: log_event(handle_func, e)

Gets the handler's method once (specifically, you get a "bound method" object gluing the object and the underlying function object together), and only then you create the anonymous function and overwrite handler.handle.