Читать книгу Professional Python - Luke Sneeringer - Страница 4
Part I
Functions
Chapter 1
Decorators
Decorator Syntax
ОглавлениеMost times that developers use decorators to decorate a function, they are only interested in the final, decorated function. Keeping a reference to the undecorated function is ultimately superfluous.
Because of this (and also for purposes of clarity), it is undesirable to define a function, assign it to a particular name, and then immediately reassign the decorated function to the same name.
Therefore, Python 2.5 introduced a special syntax for decorators. Decorators are applied by prepending an @
character to the name of the decorator and adding the line (without the implied decorator's method signature) immediately above the decorated function's declaration.
Following is the preferred way to apply a decorated_by
decorator to the add
method:
Note again that no method signature is being provided to @decorated_by
. The decorator is assumed to take a single, positional argument, which is the method being decorated. (You will see a method signature in some cases, but with other provided arguments. This is discussed later in this chapter.)
This syntax allows the decorator to be applied where the function is declared, which makes it easier to read the code and immediately realize that the decorator is in play. Readability counts.
Order of Decorator Application
When is a decorator applied? When the @
syntax is being used, decorators are applied immediately after the decorated callable is created. Therefore, the two examples shown of how to apply decorated_by
to add
are exactly equivalent. First, the add
function is created, and then, immediately after that, it is wrapped with decorated_by
.
One important thing to note about this is that it is possible to use multiple decorators on a single callable (just as it is possible to wrap function calls multiple times).
However, note that if you use multiple decorators using the @
syntax, they are applied in order, from bottom to top. This may be counterintuitive at first, but it makes sense given what the Python interpreter is actually doing.
Consider the following function with two decorators applied:
The first thing that occurs is that the add
function is created by the interpreter. Then, the decorated_by
decorator is applied. This decorator returns a callable (as all decorators do), which is then sent to also_decorated_by
, which does the same; the latter result is assigned to add
.
Remember that the application of decorated_by
is syntactically equivalent to the following:
The previous two-decorator example is syntactically equivalent to the following:
In both cases, the also_decorated_by
decorator comes first as a human reads the code. However, the decorators are applied bottom to top for the same reason that the functions are resolved from innermost to outermost. The same principles are at work.
In the case of a traditional function call, the interpreter must first resolve the inner function call in order to have the appropriate object or value to send to the outer call.
With a decorator, first the add
function is created normally.
Then, the @decorated_by
decorator is called, being sent the add
function as its decorated method.
The @decorated_by
function returns its own callable (in this case, a modified version of add
). That value is what is then sent to @also_decorated_by
in the final step.
When applying decorators, it is important for you to remember that they are applied bottom to top. Many times, order does matter.