简体   繁体   中英

How parameters pass in decorator of python?

def require(role):
    def wrapper(fn):
         def new_fn(*args, **kwargs):
             if not role in kwargs.get('roles', []):
                 print("%s not in %s" % (role, kwargs.get('roles', [])))
                 raise Exception("Unauthorized")
             return fn(*args, **kwargs)
         return new_fn
    return wrapper

@require('admin')
def get_users(**kwargs):
    return ('Alice', 'Bob')

Above code parameterizes the decorator require with admin . It seems to that function get_users passes to the parameter fn of wrapper . However, how the get_users passes to the parameter fn ?

Here get_users() does not pass the the parameter fn

since the function get_users() is bound to the decorator require

so the decorator is being called first, while your object/reference of get_users() is passed as an argument

for details refer https://wiki.python.org/moin/PythonDecorators

When a function is defined inside another function, as happens here (in fact, there are two levels of this here), the inner function(s) get access to all the outer function's variables. So it's not necessary to explicitly pass role or fn to the inner functions.

Here's what's happening:

  1. require() is called with role set to "admin" .
  2. The require() function defines another function, wrapper() , which it returns. (As an aside, this function is not well named: it is the one that does the wrapping, not the one that actually serves as the wrapper. It should probably be called wrap() or decorate() .)
  3. wrapper() is passed the function get_users() .
  4. wrapper() creates a new function, new_fn() , to be called in place of get_users() , and returns new_fn() . (Again, this is not the greatest name, it should probably be called wrapper() since it's the wrapper for the function being decorated.)

Now, because of the aforementioned situation where inner functions have access to all the outer functions' variables (called a "closure"), new_fn() has access to both fn , which is the function it wrapped ( get_users() ) and also the role parameter that was originally passed to require() . So it can check the user's role to see if the user is allowed to call that function, and then, if permitted, call the function and return the result, thereby serving as a substitute for get_users() with added functionality wrapped around the original function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM