什么是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制作最美应用的爬虫
Oct 28 Python
Python利用Nagios增加微信报警通知的功能
Feb 18 Python
python 实现删除文件或文件夹实例详解
Dec 04 Python
Python 多线程的实例详解
Sep 07 Python
Python中pandas模块DataFrame创建方法示例
Jun 20 Python
基于python历史天气采集的分析
Feb 14 Python
flask 使用 flask_apscheduler 做定时循环任务的实现
Dec 10 Python
Python 脚本的三种执行方式小结
Dec 21 Python
使用python实现哈希表、字典、集合操作
Dec 22 Python
Python安装与卸载流程详细步骤(图解)
Feb 20 Python
Python+Opencv身份证号码区域提取及识别实现
Aug 25 Python
python 实现网易邮箱邮件阅读和删除的辅助小脚本
Mar 01 Python
Python经常使用的一些内置函数
python处理json数据文件
Python几种酷炫的进度条的方式
Python通过loop.run_in_executor执行同步代码 同步变为异步
Python Pandas解析读写 CSV 文件
宝塔更新Python及Flask项目的部署
python模板入门教程之flask Jinja
You might like
PHP模板引擎SMARTY
2006/10/09 PHP
ajax取消挂起请求的处理方法
2013/03/18 PHP
注释PHP和html混合代码的小技巧(分享)
2016/11/03 PHP
详解php反序列化
2020/06/10 PHP
imgAreaSelect 中文文档帮助说明
2011/10/08 Javascript
用JQUERY增删元素的代码
2012/02/14 Javascript
IE6浏览器下resize事件被执行了多次解决方法
2012/12/11 Javascript
Jquery下EasyUI组件中的DataGrid结果集清空方法
2014/01/06 Javascript
jQuery模拟点击A标记示例参考
2014/04/17 Javascript
学习JavaScript设计模式之状态模式
2016/01/08 Javascript
讲解JavaScript的Backbone.js框架的MVC结构设计理念
2016/02/14 Javascript
javascript结合Flexbox简单实现滑动拼图游戏
2016/02/18 Javascript
javascript断点调试心得分享
2016/04/23 Javascript
基于JS实现发送短信验证码后的倒计时功能(无视页面刷新,页面关闭不进行倒计时功能)
2016/09/02 Javascript
浅谈JS中的三种字符串连接方式及其性能比较
2016/09/02 Javascript
javascript动画之磁性吸附效果篇
2016/12/09 Javascript
BootStrap 导航条实例代码
2017/05/18 Javascript
vue项目webpack中Npm传递参数配置不同域名接口
2018/06/15 Javascript
koa2使用ejs和nunjucks作为模板引擎的使用
2018/11/27 Javascript
[04:54]DOTA2-DPC中国联赛1月31日Recap集锦
2021/03/11 DOTA
对于Python的Django框架使用的一些实用建议
2015/04/03 Python
Python中的默认参数实例分析
2018/01/29 Python
python的dataframe和matrix的互换方法
2018/04/11 Python
django反向解析和正向解析的方式
2018/06/05 Python
python3中zip()函数使用详解
2018/06/29 Python
详解python调用cmd命令三种方法
2019/07/08 Python
Python 多线程,threading模块,创建子线程的两种方式示例
2019/09/29 Python
基于python3监控服务器状态进行邮件报警
2019/10/19 Python
python 实现目录复制的三种小结
2019/12/04 Python
Python unittest 自动识别并执行测试用例方式
2020/03/09 Python
opencv 图像轮廓的实现示例
2020/07/08 Python
教师节商场活动方案
2014/02/13 职场文书
学校端午节活动方案
2014/08/23 职场文书
表扬稿格式范文
2015/01/16 职场文书
银行客户经理岗位职责
2015/04/09 职场文书
「玫瑰之王的葬礼」舞台剧主视觉图公开
2022/03/21 日漫