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.


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!