Apologies this is a very broad question.
The code below is a fragment of something found on the web. The key thing I am interested in is the line beginning @protected – I am wondering what this does and how it does it? It appears to be checking that a valid user is logged in prior to executing the do_upload_ajax function. That looks like a really effective way to do user authentication. I don’t understand the mechanics of this @ function though – can someone steer me in the right direction to explain how this would be implemented in the real world? Python 3 answers please. thanks.
def do_upload_ajax(): data = bottle.request.files.get('data') if data.file: size = 0
Take a good look at this enormous answer/novel. It’s one of the best explanations I’ve come across.
The shortest explanation that I can give is that decorators wrap your function in another function that returns a function.
This code, for example:
def foo(a): print a
would be equivalent to this code if you remove the decorator syntax:
def bar(a): print a foo = decorate(bar)
Decorators sometimes take parameters, which are passed to the dynamically generated functions to alter their output.
Another term you should read up on is closure, as that is the concept that allows decorators to work.
A decorator is a function that takes a function as its only parameter and returns a function. This is helpful to “wrap” functionality with the same code over and over again.
We use @func_name to specify a decorator to be applied on another function.
Following example adds a welcome message to the string returned by fun(). Takes fun() as parameter and returns welcome().
def decorate_message(fun): # Nested function def addWelcome(site_name): return "Welcome to " + fun(site_name) # Decorator returns a function return addWelcome def site(site_name): return site_name; print site("StackOverflow") Out: "Welcome to StackOverflow"
Decorators can also be useful to attach data (or add attribute) to functions.
A decorator function to attach data to func
def attach_data(func): func.data = 3 return func def add (x, y): return x + y print(add(2, 3)) # 5 print(add.data) # 3
The decorator syntax:
def do_upload_ajax(): "..."
is equivalent to
def do_upload_ajax(): "..." do_upload_ajax = protected(check_valid_user)(do_upload_ajax)
but without the need to repeat the same name three times. There is nothing more to it.
For example, here’s a possible implementation of
import functools def protected(check): def decorator(func): # it is called with a function to be decorated # preserve original name, docstring, etc def wrapper(*args, **kwargs): check(bottle.request) # raise an exception if the check fails return func(*args, **kwargs) # call the original function return wrapper # this will be assigned to the decorated name return decorator
A decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it. Python allows “nested” functions ie (a function within another function).
Python also allows you to return functions from other functions.
Let us say, your original function was called orig_func().
def orig_func(): #definition print("Wheee!") orig_func() #calling
Run this file, the orig_func() gets called and prints. “wheee”.
Now, let us say, we want to modify this function, to do something before this calling this function and also something after this function.
So, we can do like this, either by option 1 or by option 2
def orig_func(): print("Wheee!") print "do something before" orig_func() print "do something after"
Note that we have not modified the orig_func. Instead, we have made changes outside this function.
But may be, we want to make changes in a such a way that when orig_func is called, we are able to do something before and after calling the function. So, this is what we do.
def orig_func(): print "do something before" print("Whee!") print "do something after" orig_func()
We have achieved our purpose. But at what cost? We had to modify the code of orig_func. This may not always be possible, specially, when someone else has written the function. Yet we want that when this function is called, it is modified in such a way, that something before and/or after can be done. Then the decorator helps us to do this, without modifying the code of orig_func. We create a decorator and can keep the same name as before. So, that if our function is called, it is transparently modified. We go through following steps.
a. Define the decorator. In the docorator,
1) write code to do something before orig_func, if you want to.
2) call the orig_func, to do its job.
3) write code to do something after orig_func, if you want to.
b. Create the decorator
c. Call the decorator.
Here is how we do it.
#-------- orig_func already given ---------- def orig_func(): print("Wheee!") #------ write decorator ------------ def my_decorator(some_function): def my_wrapper(): print "do something before" #do something before, if you want to some_function() print "do something after" #do something after, if you want to return my_wrapper #------ create decorator and call orig func -------- orig_func = my_decorator(orig_func) #create decorator, modify functioning orig_func() #call modified orig_func
Note, that now orig_func has been modified through the decorator. So, now when you call orig_func(), it will run my_wrapper, which will do three steps, as already outlined.
Thus you have modified the functioning of orig_func, without modifying the code of orig_func, that is the purpose of the decorator.
First, we need to understand why we need Decorator.
Need for decorator:
We want to use the function of already built-in Library from Python which can perform our desired task.
But problem is that we don’t want exact function output. We want customized output.
The trick is that we can’t change the original code of the function. here decorator comes to our help.
Decorator takes our required function as input, wraps it in a wrapper function and
does 3 things:
- do something before.
- then call the desired function().
- do something after.
def my_decorator(desired_function): def my_wrapper(): print "do something before" #do something before, if you want to desired_function() print "do something after" #do something after, if you want to return my_wrapper desired_func = my_decorator(desired_func()) #create decorator desired_func() #calling desired_func()
Decorator is just a function that takes another function as an argument
def get_function_name_dec(func): def wrapper(*arg): function_returns = func(*arg) # What our function returns return func.__name__ + ": " + function_returns return wrapper def hello_world(): return "Hi" print(hello_world())