Python全景系列之装饰器使用的全面讲解
作者:techlead_krischang 发布时间:2021-08-21 01:04:12
Python 装饰器深入探讨
在 Python 中,装饰器提供了一种简洁的方式,用来修改或增强函数和类的行为。装饰器在语法上表现为一个前置于函数或类定义之前的特殊标记:
@simple_decorator
def hello_world():
print("Hello, world!")
在这个例子中,simple_decorator
是一个装饰器,它作用于下方的 hello_world
函数。装饰器在概念上就像一个包装器,它可以在被装饰的函数执行前后插入任意的代码,进而改变被装饰函数的行为。
参数化装饰器
我们还可以进一步将装饰器参数化,这让装饰器的行为更具灵活性。比如,我们可以定义一个装饰器,让它在函数执行前后打印自定义的消息:
def message_decorator(before_message, after_message):
def decorator(func):
def wrapper(*args, **kwargs):
print(before_message)
result = func(*args, **kwargs)
print(after_message)
return result
return wrapper
return decorator
@message_decorator("Start", "End")
def hello_world():
print("Hello, world!")
在这个例子中,message_decorator
是一个参数化装饰器,它接受两个参数,分别代表函数执行前后要打印的消息。
理解装饰器的工作原理
在 Python 中,函数是第一类对象。这意味着函数和其他对象一样,可以作为变量进行赋值,可以作为参数传给其他函数,可以作为其他函数的返回值,甚至可以在一个函数里面定义另一个函数。这个特性是实现装饰器的基础。
def decorator(func):
def wrapper():
print('Before function execution')
func()
print('After function execution')
return wrapper
def hello_world():
print('Hello, world!')
decorated_hello = decorator(hello_world)
decorated_hello()
在这个例子中,decorator
函数接收一个函数 hello_world
作为参数,并返回了一个新的函数 wrapped_func
。这个新函数在 hello_world
函数执行前后分别打印一条消息。我们可以看到,装饰器实际上是一个返回函数的函数。
函数签名保持
默认情况下,装饰器会“掩盖”掉原函数的名字和文档字符串。这是因为在装饰器内部,我们返回了一个全新的函数。我们可以使用 functools.wraps
来解决这个问题:
import functools
def decorator(func):
@functools.wraps(func)
def wrapper():
print('Before function execution')
func()
print('After function execution')
return wrapper
@decorator
def hello_world():
"Prints 'Hello, world!'"
print('Hello, world!')
print(hello_world.__name__)
print(hello_world.__doc__)
这样,使用装饰器后的函数名和文档字符串能够保持不变。
Python 装饰器的应用实例
装饰器在实际的 Python 编程中有许多应用场景,比如日志记录、性能测试、事务处理、缓存、权限校验等。
一个常见的应用就是使用装饰器进行日志记录:
import logging
def log_decorator(func):
logging.basicConfig(level=logging.INFO)
def wrapper(*args, **kwargs):
logging.info(f'Running "{func.__name__}" with arguments {args} and kwargs {kwargs}')
result = func(*args, **kwargs)
logging.info(f'Finished "{func.__name__}" with result {result}')
return result
return wrapper
@log_decorator
def add(x, y):
return x + y
这个装饰器记录了函数的名称,函数调用的参数,以及函数返回的结果。
装饰器链
Python 允许我们将多个装饰器应用到一个函数上,形成一个装饰器链。例如,我们可以同时应用日志装饰器和性能测试装饰器:
import time
import logging
from functools import wraps
def log_decorator(func):
logging.basicConfig(level=logging.INFO)
@wraps(func)
def wrapper(*args, **kwargs):
logging.info(f'Running "{func.__name__}" with arguments {args} and kwargs {kwargs}')
result = func(*args, **kwargs)
logging.info(f'Finished "{func.__name__}" with result {result}')
return result
return wrapper
def timer_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f'Function "{func.__name__}" took {end_time - start_time} seconds to run.')
return result
return wrapper
@log_decorator
@timer_decorator
def add(x, y):
time.sleep(2)
return x + y
在这个例子中,@log_decorator
和 @timer_decorator
两个装饰器被同时应用到 add
函数上,它们分别负责记录日志和测量函数运行时间。
One More Thing: 自动注册装饰器
一个有趣的装饰器应用是自动注册。这个装饰器会在装饰函数时自动将函数添加到一个列表或字典中,这样我们就可以在程序的其他地方访问到这个列表或字典,知道有哪些函数被装饰过。
# 装饰器将函数注册到一个列表中
def register_decorator(func_list):
def decorator(func):
func_list.append(func)
return func
return decorator
# 自动注册函数
registered_functions = []
@register_decorator(registered_functions)
def foo():
pass
@register_decorator(registered_functions)
def bar():
pass
print(registered_functions) # 输出: [<function foo at 0x10d38d160>, <function bar at 0x10d38d1f0>]
这个装饰器可以用于自动注册路由、插件系统、命令行参数处理等场景,能够大大提高代码的灵活性和可扩展性。
来源:https://www.cnblogs.com/xfuture/p/17445659.html


猜你喜欢
- 微信小程序实现人脸识别,具体应用场景 前端实现人脸信息采集 拍到正面照片 发送给后端该方法暂
- 现在大家常用的桌面操作系统有:Windows、Mac OS、ubuntu,其中Mac OS 和 ubuntu上都会自带python。这里我们
- 一、简单介绍正则表达式是一种小型的、高度专业化的编程语言,并不是python * 有的,是许多编程语言中基础而又重要的一部分。在python中
- 当我们在Vue.js项目中引用图片时,关于图片路径有以下几种情形:使用一我们在data里面定义好图片路径imgUrl:'../ass
- 在服务端程序开发的过程中,cookie经常被用于验证用户登录。golang 的 net/http 包中自带 http cookie的定义,下
- MySql总是定时弹出一个MySQLInstallerConsole.exe的窗口,如何解决呐?这貌似是一条安装命令,Installing
- 本文实例讲述了Python使用Selenium模块模拟浏览器抓取斗鱼直播间信息。分享给大家供大家参考,具体如下:import timefro
- 了解SQL Server 2005数据库的朋友可能都知道,tempdb系统数据库是一个全局资源,可供连接到SQL Server 2005实例
- 一、需求介绍该需求主要是分析彩票的历史数据,彩票的名称为:1、极速飞艇链接:https://www.dsn665.com/view/jisu
- python2.7在内存管理上相比python3还是有些坑的,其释放后的内存仍然保留在python的内存池中,不被系统所用。python循环
- 本文实例讲述了GO语言延迟函数defer用法。分享给大家供大家参考。具体分析如下:defer 在声明时不会立即执行,而是在函数 return
- 在分析查询性能时,考虑EXPLAIN关键字同样很管用。EXPLAIN关键字一般放在SELECT查询语句的前面,用于描述MySQL如何执行查询
- 如下所示:import numpy as np# 等差数列print(np.linspace(0.1, 1, 10, endpoint=Tr
- 本文实例为大家分享了vuex实现购物车功能的具体代码,供大家参考,具体内容如下文件目录如下:购物车组件<template> &n
- 什么是pyQt5首先我们来说说什么是pyQt5。搞过GUI界面设计的童鞋一定都了解过微软的MFC。当然了,个人感觉MFC不是一个非常优雅的U
- 今天自己写个楼层效果,有一点烦躁,小地方犯错误。各位大神来修改不足啊!!!<!DOCTYPE html><html lan
- 一、简介Python 内置了 requests 模块,该模块主要用来发送 HTTP 请求,requests 模块比 urllib
- oracle 11g的监听日志和警告日志都是在/u01/oracle/diag/tnslsnr/oracle/listener目录和/u01
- 方法:通过desc:都无法实现:方法一:select sp.productid,sp.productname,ss.sku from sp_
- Oracle中大文本数据类型Clob 长文本类型 (MySQL中不支持,使用的是text)Blob 二进