Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of functools.partial in a decorator that attaches function as attribute of object

In Python Cookbook section 9.5. Defining a Decorator with User Adjustable Attributes I've been having difficulty wrapping my head around the use of functools.partial in the following code:

# Utility decorator to attach a function as an attribute of obj
def attach_wrapper(obj, func=None):
    if func is None:
        return partial(attach_wrapper, obj)
    setattr(obj, func.__name__, func)
    return func

Is its use to prevent shadowing of attributes if composing multiple decorators? I am not totally clear to why partial would be used here and would appreciate any clarification.

like image 855
Matt Eding Avatar asked Jan 04 '18 15:01

Matt Eding


1 Answers

I'll try two explanations. Here's the short one. These decorators are equivalent.

def attach_wrapper(obj, func=None):
    if func is None:
        return partial(attach_wrapper, obj)
    setattr(obj, func.__name__, func)
    return func


def my_attach_wrapper(obj):
    def wrapper(func):
        setattr(obj, func.__name__, func)
        return func
    return wrapper

And here's the long version. This is a step-by-step of what the wrapper does.

@attach_wrapper(wrapper)
def set_level(newlevel):
    level = newlevel

is equivalent to:

def set_level(newlevel):
   level = newlevel

set_level = attach_wrapper(wrapper)(set_level)

first, attach_wrapper(wrapper, func=None) returns a partial function that takes one argument, func. for simplicity, let's call this new function partial_attach. And we can define it like so:

def partial_attach(func):
    setattr(wrapper, func.__name__, func)
    return func

when attach_wrapper(wrapper, func=None) returns partial_attach, we have:

set_level = partial_attach(set_level)

since that returns set_level, set_level is equal to itself. But now wrapper has an attribute, set_level, which points to the same function.

like image 188
e.s. Avatar answered Oct 07 '22 04:10

e.s.