SoFunction
Updated on 2024-10-30

Python decorator introductory learning tutorial (nine steps to learn)

A decorator is an advanced Python syntax. A decorator can work on a function, method or class. In Python, we have a variety of ways to work with functions and classes, such as in Python closures, we see the function object as the return result of a function. As compared to other ways, decorator syntax is simple and code is highly readable. Therefore, decorators have a wide range of applications in Python projects.

This was presented at the Python Learning Group, where learning now and practicing more is a good way to learn.

Step 1: The simplest function, ready to attach additional functionality

# -*- coding:gbk -*-
'''Example 1: The simplest function, called twice'''
def myfunc():
print("myfunc() called.")
myfunc()
myfunc() 

Step 2: Use decorative functions to attach additional functionality before and after the function is executed

# -*- coding:gbk -*-
'''Example 2: Replacement Function (Decoration)
The argument of the decorated function is the decorated function object, and the original function object is returned.
Substantive statement of decoration: myfunc = deco(myfunc)''''
def deco(func):
print("before myfunc() called.")
func()
print(" after myfunc() called.")
return func
def myfunc():
print(" myfunc() called.")
myfunc = deco(myfunc)
myfunc()
myfunc() 

Step 3: Decorate the function with syntactic sugar @

# -*- coding:gbk -*-
'''Example 3: Decorating a function with the syntactic sugar @ is equivalent to "myfunc = deco(myfunc)"
But it turns out that the new function is only called the first time, and the original function is called one more time.'''
def deco(func):
print("before myfunc() called.")
func()
print(" after myfunc() called.")
return func
@deco
def myfunc():
print(" myfunc() called.")
myfunc()
myfunc() 

Step 4: Use inline wrapper functions to ensure that every new function is called

# -*- coding:gbk -*-
'''Example 4: Using an inline wrapper function to ensure that a new function is called every time.
The formal parameter and return value of the embedded wrapper function are the same as the original function, and the decorator function returns the embedded wrapper function object.'''
def deco(func):
def _deco():
print("before myfunc() called.")
func()
print(" after myfunc() called.")
# Instead of returning func, you should actually return the return value of the original function
return _deco
@deco
def myfunc():
print(" myfunc() called.")
return 'ok'
myfunc()
myfunc() 

Step 5: Decorating functions with parameters

# -*- coding:gbk -*-
'''Example 5: Decorating a function with parameters.
The formal parameter and return value of the embedded wrapped function are the same as the original function, and the decorated function returns the object of the embedded wrapped function.'''
def deco(func):
def _deco(a, b):
print("before myfunc() called.")
ret = func(a, b)
print(" after myfunc() called. result: %s" % ret)
return ret
return _deco
@deco
def myfunc(a, b):
print(" myfunc(%s,%s) called." % (a, b))
return a + b
myfunc(1, 2)
myfunc(3, 4) 

Step 6: Decorate a function with an indeterminate number of parameters

# -*- coding:gbk -*-
'''Example 6: Decorating a function with an indeterminate number of arguments.
Arguments with (*args, **kwargs), auto-adapting to variable and named arguments.'''
def deco(func):
def _deco(*args, **kwargs):
print("before %s called." % func.__name__)
ret = func(*args, **kwargs)
print(" after %s called. result: %s" % (func.__name__, ret))
return ret
return _deco
@deco
def myfunc(a, b):
print(" myfunc(%s,%s) called." % (a, b))
return a+b
@deco
def myfunc2(a, b, c):
print(" myfunc2(%s,%s,%s) called." % (a, b, c))
return a+b+c
myfunc(1, 2)
myfunc(3, 4)
myfunc2(1, 2, 3)
myfunc2(3, 4, 5) 

Step 7: Make the decorator take parameters

# -*- coding:gbk -*-
'''Example 7: Based on example 4, let the decorator take parameters.
Compared to the previous example, there is an extra layer of wrapping on the outside.
The name of the decorator function should actually be more meaningful'''
def deco(arg):
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, arg))
func()
print(" after %s called [%s]." % (func.__name__, arg))
return __deco
return _deco
@deco("mymodule")
def myfunc():
print(" myfunc() called.")
@deco("module2")
def myfunc2():
print(" myfunc2() called.")
myfunc()
myfunc2() 

Step 8: Make the decorator take class parameters

# -*- coding:gbk -*-
'''Example 8: Decorator with class parameters'''
class locker:
def __init__(self):
print("locker.__init__() should be not called.")
@staticmethod
def acquire():
print("() called.(This is a static method.)")
@staticmethod
def release():
print(" () called.(No object instance required)")
def deco(cls):
'''cls must implement acquire and release static methods'''
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, cls))
()
try:
return func()
finally:
()
return __deco
return _deco
@deco(locker)
def myfunc():
print(" myfunc() called.")
myfunc()
myfunc() 

Step 9: The decorator takes class parameters and splits the public class into other py files, while demonstrating the application of multiple decorators to a single function

# -*- coding:gbk -*-
''': public class for example'''
class mylocker:
def __init__(self):
print("mylocker.__init__() called.")
@staticmethod
def acquire():
print("() called.")
@staticmethod
def unlock():
print(" () called.")
class lockerex(mylocker):
@staticmethod
def acquire():
print("() called.")
@staticmethod
def unlock():
print(" () called.")
def lockhelper(cls):
'''cls must implement acquire and release static methods'''
def _deco(func):
def __deco(*args, **kwargs):
print("before %s called." % func.__name__)
()
try:
return func(*args, **kwargs)
finally:
()
return __deco
return _deco 
# -*- coding:gbk -*-

'''Example 9: Decorator with class parameter and splitting public class to other py file

Also demonstrates applying multiple decorators to a single function.'''

from mylocker import *
class example:
@lockhelper(mylocker)
def myfunc(self):
print(" myfunc() called.")
@lockhelper(mylocker)
@lockhelper(lockerex)
def myfunc2(self, a, b):
print(" myfunc2() called.")
return a + b
if __name__=="__main__":
a = example()
()
print(())
print(a.myfunc2(1, 2))
print(a.myfunc2(3, 4)) 

Above we have shared the Python Decorator Introductory Learning Tutorial (Nine Steps to Learn), I hope it will be helpful to you.