Master Python Decorators: From Basics to Advanced Patterns
This article provides a comprehensive guide to Python decorators, covering their core concepts, practical use‑cases, step‑by‑step creation of simple, parameterized, class‑based, and advanced decorators, complete with runnable code examples.
大家好,我是明哥。今天给大家分享一下关于装饰器的知识点,内容非常干,全程高能,认真吸收看完,一定会对装饰器有更深的理解。
Hello,装饰器
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等。
装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
装饰器的使用方法很固定
先定义一个装饰器(帽子)
再定义你的业务函数或者类(人)
最后把这装饰器(帽子)扣在这个函数(人)头上
就像下面这样子
# 定义装饰器
def decorator(func):
def wrapper(*args, **kw):
return func()
return wrapper
# 定义业务函数并进行装饰
@decorator
def function():
print("hello, decorator")实际上,装饰器并不是编码必须性,意思是说,你不使用装饰器完全可以,它的出现应该使我们的代码更加优雅,代码结构更清晰;将实现特定功能的代码封装成装饰器,提高代码复用率,增强代码可读性。
第一种:普通装饰器
首先咱来写一个最普通的装饰器,它实现的功能是:
在函数执行前,先记录一行日志
在函数执行完,再记录一行日志
# 这是装饰器函数,参数 func 是被装饰的函数
def logger(func):
def wrapper(*args, **kw):
print('我准备开始执行:{} 函数了:'.format(func.__name__))
# 真正执行的是这行。
func(*args, **kw)
print('主人,我执行完啦。')
return wrapper假如,我的业务函数是,计算两个数之和。写好后,直接给它带上帽子。
@logger
def add(x, y):
print('{} + {} = {}'.format(x, y, x+y))然后执行一下 add 函数。
add(200, 50)输出:
我准备开始执行:add 函数了:
200 + 50 = 250
我执行完啦。第二种:带参数的函数装饰器
装饰器的用法还远不止如此,深究下去,还大有文章。装饰器本身是一个函数,不能接收参数,只能对被装饰函数执行固定逻辑。若需要根据不同场景调整逻辑,需要让装饰器接受参数。
例如实现一个可以定时发送邮件的任务的装饰器:
@periodic_task(spacing=60)
def send_mail():
pass
@periodic_task(spacing=86400)
def ntp():
pass下面演示一个自定义带参数的装饰器,根据国籍在函数执行前打印不同的问候语:
# 小明,中国人
@say_hello("china")
def xiaoming():
pass
# jack,美国人
@say_hello("america")
def jack():
pass def say_hello(contry):
def wrapper(func):
def deco(*args, **kwargs):
if contry == "china":
print("你好!")
elif contry == "america":
print("hello.")
else:
return
func(*args, **kwargs)
return deco
return wrapper执行:
xiaoming()
print("------------")
jack()输出:
你好!
------------
hello.第三种:不带参数的类装饰器
基于类实现的装饰器必须实现 __init__ 和 __call__ 两个方法。
class logger(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("[INFO]: the function {func}() is running...".format(func=self.func.__name__))
return self.func(*args, **kwargs)
@logger
def say(something):
print("say {}!".format(something))
say("hello")第四种:带参数的类装饰器
通过在类的 __init__ 中接受参数,可以让装饰器根据不同的日志级别输出不同的前缀。
class logger(object):
def __init__(self, level='INFO'):
self.level = level
def __call__(self, func):
def wrapper(*args, **kwargs):
print("[{level}]: the function {func}() is running...".format(level=self.level, func=func.__name__))
func(*args, **kwargs)
return wrapper
@logger(level='WARNING')
def say(something):
print("say {}!".format(something))
say("hello")第五种:使用偏函数与类实现装饰器
利用 functools.partial 可以把类包装成带参数的装饰器。
import time
import functools
class DelayFunc:
def __init__(self, duration, func):
self.duration = duration
self.func = func
def __call__(self, *args, **kwargs):
print(f'Wait for {self.duration} seconds...')
time.sleep(self.duration)
return self.func(*args, **kwargs)
def delay(duration):
"""装饰器:推迟某个函数的执行。"""
return functools.partial(DelayFunc, duration)
@delay(duration=2)
def add(a, b):
return a+b第六种:能装饰类的装饰器
装饰器也可以用于类,实现单例模式:
instances = {}
def singleton(cls):
def get_instance(*args, **kw):
cls_name = cls.__name__
if cls_name not in instances:
instance = cls(*args, **kw)
instances[cls_name] = instance
return instances[cls_name]
return get_instance
@singleton
class User:
def __init__(self, name):
self.name = nameSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Python Crawling & Data Mining
Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
