Systematic learning of Python - Decorators: Basic knowledge - [Decorator Nesting]

Category Catalog: General Catalog of "Systematic Learning Python"


Sometimes, one decorator is not enough. For example, suppose we write two function decorators that will be used during development. One is used to test the parameter type before the function is called, and the other is used to test the return value type after the function is called. We can use either one independently, but if we want to use both on a single function, what we really need is a way to nest both so that the result of one decorator is the result of the other decorator The decorated function. It doesn't matter which decorator is nested, as long as both steps are run on subsequent calls. To support the expansion of multiple nested steps in this way, the decorator syntax allows us to add multiple layers of wrapper logic to a decorated function or method. When using this feature, each decorator must appear on its own line. The decorator syntax for this form is:

@A
@B
@C
def f():
	pass

This runs the same as the following code:

def f():
	pass

f = A(B(C(f)))

Here, the original function is passed into three different decorators, and the final callable is assigned back to the original name. Each decorator handles the result of the previous one, which may be the original function or an intervening wrapper.

If all decorators are inserted into the wrapper, the direct effect is that when the original function name is called, three different layers of the wrapped object logic will be called, thus extending the original function in three different ways. When the original function name is subsequently called, the last decorator listed above is applied first, which is also the most deeply nested decorator.

As with functions, multiple class decorators result in multiple nested function calls and can result in multiple layers and steps of wrapper logic around instance creation calls. For example the following code:

@A
@B
@C
class Class_A:
	pass

X = Class_A()

This is equivalent to the following code:

class Class_A:
	pass

Class_A = A(B(C(Class_A )))
X = Class_A ()

Each decorator is free to return the original class or the inserted wrapper object. With wrappers, when Class_Aan instance of the original class is requested, the call is redirected to Athe wrapper object provided by the decorator. These objects can have many different roles - for example, they can track and validate properties B. Caccess, both steps will be run on subsequent requests.

For example, the following decorator does nothing but returns the decorated function:

def d1(F):
	return F

def d2(F):
	return F

def d3(F):
	return F

@d1
@d2
@d3
def func():
	print('machinelearning.blog.csdn.net')

func()

Output:

machinelearning.blog.csdn.net

The same syntax works on classes as well as decorators here that do nothing. However, when decorators are inserted into a wrapper function object, they may extend the original function when called. The following code runs each decorator layer from the inside out and concatenates the results in each layer:

def d1(F):
	return lambda: 'CSDN' + F()

def d2(F):
	return lambda: 'Blog' + F()

def d3(F):
	return lambda: ':' + F()

@d1
@d2
@d3
def func():
	return 'machinelearning.blog.csdn.net'

func()

Output:

CSDNBlog:machinelearning.blog.csdn.net

We use functions here lambdato implement wrapper layers (each retaining the wrapped function in an outer scope). In practice, wrappers can take the form of functions, callable classes, etc. Well-designed decorator nesting allows us to combine extension steps in a variety of ways.

References:
[1] Mark Lutz. Python Learning Manual[M]. Machinery Industry Press, 2018.

Guess you like

Origin blog.csdn.net/hy592070616/article/details/135207466