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:
require()
is called with role
set to "admin"
. 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()
.) wrapper()
is passed the function get_users()
. 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.