Читать книгу 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.

Professional Python

Подняться наверх