Systematic learning of Python - Decorator: Function Decorator - [Decorator state retention scheme: outer scope and global variables]

Category Catalog: General Catalog of "Systematic Learning Python"


Closure functions (with enclosing defscope references and nesting def) can often achieve the same effect, especially when used with static data like decorated initial numbers. However, in the following example, we also need a counter in the outer scope that changes with each call, which is not possible in Python 2. In Python2.X, we can still rely on the classes and attributes used in the previous article, or choose other solutions. Using declarations to move state variables out of the global scope is an alternative and works in both Python 2.X and Python 3.X:

calls = 0

def tracer(func):
	def wrapper(*args, **kwargs):
		global calls
		calls += 1
		print('call %s to %s' % (calls, func.__name__))
		return func(*args, **kwargs)
	return wrapper

@tracer
def spam(a, b, c):
	print(a + b + c)

@tracer
def eggs(s, y):
	print(x ** y)

span(1, 2, 3)
span(a=4, b=5, c=6)
eggs(2, 16)
eggs(4, y=4)

Unfortunately, moving the counters out of the common global scope will allow them to be modified like this, which also means that they will be shared by every wrapped function. Unlike class instance properties, global counters are cross-program rather than per-function—the counter is incremented for any traced function call. If you compare the output of this version with the previous version, you can see the difference - a single and shared global call counter is updated every time the decorated function is called, which is incorrect:
Output results

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

Guess you like

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