什么是Python装饰器?如何定义和使用?


Posted in Python onApril 11, 2022

1.装饰器的定义

装饰器:给已有函数增加额外的功能的函数,本质上是一个闭包函数

特点:

  •     1.不修改已有函数的源代码
  •     2.不修改已有函数的调用方式
  •     3.给已有函数增加额外的功能
  •     4.代码执行时先解析装饰器
import time
 
# 装饰器原理
# def show():
#     n=0
#     for i in range(10000000):
#         n+=i
#     print('show_',n)
#
# # 定义一个闭包
# def count_time(fun):
#     def inner():
#         start=time.time()
#         fun()
#         end=time.time()
#         print(f'用时{end-start}秒')
#     return inner
#
# # 装饰器在装饰函数时的原理
# show=count_time(show)
# show()
 
# 定义装饰器(语法糖)
def count_time(fun):    # 必须要有一个参数接收被装饰函数
    def inner():
        start=time.time()
        fun()
        end=time.time()
        print(f'用时{end-start}秒')
    return inner
# 装饰器写法:@闭包的外部函数,必须在闭包定以后使用
print('解析装饰器1')
@count_time # 解释成show=count_time(show),show指向count_time函数中的inner
def show():
    n=0
    for i in range(10000000):
        n+=i
    print('show_',n)
 
print('解析装饰器2')
@count_time # 解释成display=count_time(display)
def display():
    print('Display')
 
print('正式执行...')
show()
display()

2.装饰器的通用类型的定义

(当被装饰函数有参数或者有返回值时同样适用)

'''
装饰器的通用类型的定义(当被装饰函数有参数或者有返回值时同样适用)
'''
 
def outer(func):
    def inner(*args,**kwargs):  # *为元组和列表解包,**为字典解包
        print('*'*30)
        print(args,kwargs)
        ret=func(*args,**kwargs)    # 解包,否则形参是元组或字典
        print('*'*30)
        return ret
    return inner
 
@outer
def show(name,msg):
    return str(name)+' say: '+str(msg)
 
print(show('Tom',msg='Hello'))

3.多个装饰器同时装饰一个函数

# 第一个闭包
def wrapper_div(func):
    def inner(*args,**kwargs):
        return '<div>'+func(*args,**kwargs)+'</div>'
    return inner
 
# 第二个闭包
def wrapper_p(func):
    def inner(*args,**kwargs):
        return '<p>'+func(*args,**kwargs)+'</p>'
    return inner
 
# 从下往上装饰,从上往下执行
@wrapper_div
@wrapper_p
# 定义一个函数
def show():
    return 'Short life I use Python.'
 
print(show())   #<div><p>Short life I use Python.</p></div>

4.多个装饰器同时装饰一个函数(二)

def outer1(func):
    def inner():
        print('装饰器1-1')
        func()
        print('装饰器1-2')
    return inner
 
def outer2(func):
    def inner():
        print('装饰器2-1')
        func()
        print('装饰器2-2')
    return inner
'''
1.show指向outer1.inner
2.outer1.inner.func指向outer2.inner
3.outer2.inner.func指向show
'''
@outer1
@outer2
def show():
    print('Show...')
 
show()

5.类装饰器使用方法

import time
 
class Wrapper():
    def __init__(self,func):
        self.func=func
 
    # 当类中实现了此方法时,该类的实例对象就变成了可调用对象,即可以在实例对象后面加()
    def __call__(self, *args, **kwargs):
        print('装饰内容1...')
        start=time.time()
        ret=self.func(*args,**kwargs)
        end=time.time()
        print(f'执行了{end-start}秒')
        print('装饰内容2...')
        return ret

该装饰器执行完成后,被装饰函数指向该类的实例对象
如果让被装饰函数执行,那么在类中要添加__call__方法,相当于闭包格式中的内函数
一旦被装饰函数执行调用,那么就会去执行实例对象中的__call__函数

@Wrapper    #解释成show=Wrapper(show),show变成了类的一个对象
def show():
    print('Show...')
 
show()
6.装饰器带有参数(使用带有参数的装饰器,其实是在装饰器外面又包裹了一个函数)
# @Author  : Kant
# @Time    : 2022/1/23 22:43
 
def set_args(msg):
    def outer(func):
        def inner():
            print('装饰内容',msg)
            func()
        return inner
    return outer
 
'''
使用带有参数的装饰器,其实是在装饰器外面又包裹了一个函数,使用该函数接收参数,返回的是装饰器
调用set_args()后会返回outer的地址引用,变成了@outer
'''
@set_args('Hello')
# 无论闭包函数写成什么样子,被装饰函数永远指向闭包函数的内函数
def show():
    print('Show...')
 
show()

6.使用装饰器实现自动维护路由表

路由功能:通过请求的路径,可以找到资源的地址

# 定义一个路由表字典
router_table={}
def router(url):
    def wrapper(func):
        def inner():
            print('1')
            print('inner-',func)    # 查看当前的被装饰函数是谁
            func()
        # 在这里维护路由表字典
        router_table[url]=inner # 如果写func,inner函数中的内容都不会执行
        print('路由表字典:',router_table)
        return inner
    return wrapper
 
@router('index.html')
def index():
    print('首页内容')
 
@router('center.html')
def center():
    print('个人中心')
 
@router('mail.html')
def mail():
    print('邮箱页面')
 
@router('login.html')
def login():
    print('登录页面')
 
def error():
    print('访问页面不存在')
 
def request_url(url):
    func=error
    if url in router_table:
        func=router_table[url]
    func()
 
print('开始执行函数')
request_url('index.html')
request_url('center.html')
request_url('mail.html')
request_url('test.html')
request_url('login.html')
Python 相关文章推荐
Python tempfile模块学习笔记(临时文件)
May 25 Python
Pthon批量处理将pdb文件生成dssp文件
Jun 21 Python
Python中扩展包的安装方法详解
Jun 14 Python
Python之Scrapy爬虫框架安装及简单使用详解
Dec 22 Python
在python中将list分段并保存为array类型的方法
Jul 15 Python
tensorflow之tf.record实现存浮点数数组
Feb 17 Python
深度学习入门之Pytorch 数据增强的实现
Feb 26 Python
Python生成器常见问题及解决方案
Mar 21 Python
python中adb有什么功能
Jun 07 Python
Django ORM判断查询结果是否为空,判断django中的orm为空实例
Jul 09 Python
pytorch加载语音类自定义数据集的方法教程
Nov 10 Python
利用Python脚本写端口扫描器socket,python-nmap
Jul 23 Python
Python经常使用的一些内置函数
python处理json数据文件
Python几种酷炫的进度条的方式
Python通过loop.run_in_executor执行同步代码 同步变为异步
Python Pandas解析读写 CSV 文件
宝塔更新Python及Flask项目的部署
python模板入门教程之flask Jinja
You might like
php代码架构的八点注意事项
2016/01/25 PHP
php中引用符号(&amp;)的使用详细介绍
2016/12/06 PHP
PHP将身份证正反面两张照片合成一张图片的代码
2017/04/08 PHP
thinkphp5实现无限级分类
2019/02/18 PHP
Javascript条件判断使用小技巧总结
2008/09/08 Javascript
一些实用的jQuery代码片段收集
2011/07/12 Javascript
JS保留两位小数 四舍五入函数的小例子
2013/11/20 Javascript
利用JQuery和Servlet实现跨域提交请求示例分享
2014/02/12 Javascript
js中精确计算加法和减法示例
2014/03/28 Javascript
js实现缓冲运动效果的方法
2015/04/10 Javascript
js带点自动图片轮播幻灯片特效代码分享
2015/09/07 Javascript
使用jQuery监听DOM元素大小变化
2016/02/24 Javascript
js实现碰撞检测特效代码分享
2016/10/16 Javascript
AngularJS指令用法详解
2016/11/02 Javascript
关于vue.js v-bind 的一些理解和思考
2017/06/06 Javascript
史上最全JavaScript数组去重的十种方法(推荐)
2017/08/17 Javascript
JS异步函数队列功能实例分析
2017/11/28 Javascript
实例学习JavaScript读取和写入cookie
2018/01/29 Javascript
jquery实现二级导航下拉菜单效果实例
2019/05/14 jQuery
Vue + Node.js + MongoDB图片上传组件实现图片预览和删除功能详解
2020/04/29 Javascript
利用node.js开发cli的完整步骤
2020/12/29 Javascript
Python 读取指定文件夹下的所有图像方法
2018/04/27 Python
python实战之实现excel读取、统计、写入的示例讲解
2018/05/02 Python
python 将print输出的内容保存到txt文件中
2018/07/17 Python
Python 私有化操作实例分析
2019/11/21 Python
使用python实现哈希表、字典、集合操作
2019/12/22 Python
用python监控服务器的cpu,磁盘空间,内存,超过邮件报警
2021/01/29 Python
canvas实现有递增动画的环形进度条的实现方法
2019/07/10 HTML / CSS
汇集了世界上最好的天然和有机美容产品:LoveLula
2018/02/05 全球购物
英国家居装饰品、户外家具和玻璃器皿购物网站:Rinkit.com
2019/11/04 全球购物
皇家阿尔伯特瓷器美国官网:Royal Albert美国
2020/02/16 全球购物
英国在线定做百叶窗网站:Make My Blinds
2020/08/17 全球购物
大学生通用个人的自我评价
2014/02/10 职场文书
搞笑婚庆主持词
2015/06/29 职场文书
redis 存储对象的方法对比分析
2021/08/02 Redis
python字符串拼接.join()和拆分.split()详解
2021/11/23 Python