Welcome to Python! This is a lot of questions. Let them take them one at a time. Also, just a fair warning point. This question makes your head spin for a while before everything clicks together.
For reference, here is your decorator and function, decorated with your example:
# Decorator Function def login_required(something): @wraps(something) def wrap(*args, **kwargs): if "some_admin_name" in session: return something(*args, **kwargs) else: flash("\"You shall not pass!\" - Gandalf") return redirect(url_for("login")) return wrap
What is the argument for something? Is this a request ?!
To answer this question, we must first answer what a decorator is. The answer may vary slightly depending on what type of object you are decorating. In this case, when you decorate a function, you can think of the decorator as a method / function that allows the programmer to modify the behavior of another function.
With this in mind, we can answer your question. "something" is the function / method you are about to decorate. Yes, this is a function that takes another function as an argument.
Change the language of your decorator function to make it clearer:
def login_required(function_to_wrap): @wraps(function_to_wrap) def wrap(*args, **kwargs): if "some_admin_name" in session: return function_to_wrap(*args, **kwargs) else: flash("\"You shall not pass!\" - Gandalf") return redirect(url_for("login")) return wrap
What are args and kwargs?
The short answer is that this is a Python way, allowing parameter programmers to write functions / methods that take a variable number of arguments with and without a keyword.
Usually, when you write a function, you explicitly specify the parameters. For example:
def add_these_numbers(number_1, number_2): return number_1 + number_2
This, however, is not the only way to do things. You can also use * args or ** kargs to achieve the same:
def add_these_numbers(*args): return args[0] + args[1] def add_these_numbers_too(**kwargs): return kwargs['first_number'] + kwargs['second_number']
Since it relates to your *args/**kwargs question, it is usually used in decorators, because decorators are often applied to a variety of methods that will take a wide variety of parameters.
Using args/**kwargs , your decorator method can pass which method is initially required for the method through the decorator function. If this makes your head spin, let me know and I'll try to clarify.
Change main () so that it is more clear:
# Function Being Decorated @app.route("/some/restricted/stuff") @login_required def main(html_template): return render_template(html_template, stuff = getstuff())
Why do I need to wrap the INSIDE method to use it as a decorator?
This is the hardest part of understanding decorators, in my opinion. The key understands that at its core the decorator takes on the name of the original function.
The easiest way to understand this is to use the decorator without using the convenient @ syntax. The following equivalents:
@login_required def main(): .... main = login_required(main)
Hold on to your horses, this is where it gets AWESOME! . Both of these code snippets tell Python: The "main" word should no longer refer to the main () function, but to the results of the login_required () function when the original main () function was passed as a parameter.
WAT !?
Yes. The main () call now refers to the results of the login_required (main ()) call. That is why login_required returns a nested function. The new main () should still be a function, like the old.
The difference is that now the new main function is really an instance of wrap () configured by the parameter passed to login_required ().
So ... effectively main () is now equivalent to the following:
def main(*args, **kwargs): if "some_admin_name" in session: return predecorator_main_function(*args, **kwargs) else: flash("\"You shall not pass!\" - Gandalf") return redirect(url_for("login"))
Is it only used with a jar? Could other situations be helpful?
Definitely not! Decorators are one of many cutting-edge features built right into Python. Decorators are useful in any situation when you want to make changes (relatively small in my opinion) to existing functions / methods, when you do not want to create additional functions to avoid code duplication.