什么是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 相关文章推荐
使用70行Python代码实现一个递归下降解析器的教程
Apr 17 Python
python中根据字符串调用函数的实现方法
Jun 12 Python
python之django母板页面的使用
Jul 03 Python
Python读取Excel表格,并同时画折线图和柱状图的方法
Oct 14 Python
python增加图像对比度的方法
Jul 12 Python
利用python Selenium实现自动登陆京东签到领金币功能
Oct 31 Python
python 输出列表元素实例(以空格/逗号为分隔符)
Dec 25 Python
python识别验证码图片实例详解
Feb 17 Python
Python实现获取当前目录下文件名代码详解
Mar 10 Python
python如何处理程序无法打开
Jun 16 Python
详解vscode实现远程linux服务器上Python开发
Nov 10 Python
详解如何使用Pytest进行自动化测试
Jan 14 Python
Python经常使用的一些内置函数
python处理json数据文件
Python几种酷炫的进度条的方式
Python通过loop.run_in_executor执行同步代码 同步变为异步
Python Pandas解析读写 CSV 文件
宝塔更新Python及Flask项目的部署
python模板入门教程之flask Jinja
You might like
ThinkPHP页面跳转success与error方法概述
2014/06/25 PHP
php基于base64解码图片与加密图片还原实例
2014/11/03 PHP
简单谈谈php中ob_flush和flush的区别
2014/11/27 PHP
详解WordPress中调用评论模板和循环输出评论的PHP函数
2016/01/05 PHP
Thinkphp5 微信公众号token验证不成功的原因及解决方法
2017/11/12 PHP
fancybox1.3.1 基于Jquery的插件在IE中图片显示问题
2010/10/01 Javascript
上传的js验证(图片/文件的扩展名)
2013/04/25 Javascript
PHP使用方法重载实现动态创建属性的get和set方法
2014/11/17 Javascript
JS清除选择内容的方法
2015/01/29 Javascript
js实现网页右上角滑出会自动消失大幅广告的方法
2015/02/27 Javascript
jQuery插件实现控制网页元素动态居中显示
2015/03/24 Javascript
js实现类似菜单风格的TAB选项卡效果代码
2015/08/28 Javascript
bootstrap输入框组代码分享
2016/06/07 Javascript
JavaScript提升性能的常用技巧总结【经典】
2016/06/20 Javascript
Vuejs第七篇之Vuejs过渡动画案例全面解析
2016/09/05 Javascript
jQuery实现贪吃蛇小游戏(附源码下载)
2017/03/04 Javascript
Vue2 使用 Echarts 创建图表实例代码
2017/05/18 Javascript
微信小程序之电影影评小程序制作代码
2017/08/03 Javascript
React Form组件的实现封装杂谈
2018/05/07 Javascript
jQuery实现的页面弹幕效果【测试可用】
2018/08/17 jQuery
在create-react-app中使用sass的方法示例
2018/10/01 Javascript
使用异步controller与jQuery实现卷帘式分页
2019/06/18 jQuery
Python中使用wxPython开发的一个简易笔记本程序实例
2015/02/08 Python
使用Python编写一个在Linux下实现截图分享的脚本的教程
2015/04/24 Python
Python字符串处理的8招秘籍(小结)
2019/08/13 Python
Python3 用什么IDE开发工具比较好
2020/11/28 Python
Lululemon加拿大官网:加拿大知名体育服装零售商
2019/04/12 全球购物
俄罗斯游戏商店:Buka
2020/03/01 全球购物
我想声明一个指针并为它分配一些空间, 但却不行。这些代码有什么 问题?char *p; *p = malloc(10);
2016/10/06 面试题
北京SQL新华信咨询
2016/09/30 面试题
银行会计职员个人的自我评价
2013/09/29 职场文书
厂长岗位职责
2014/02/19 职场文书
委托书的写法
2014/09/16 职场文书
个人欠条范本
2015/07/03 职场文书
python中sqllite插入numpy数组到数据库的实现方法
2021/06/21 Python
关于MySQL临时表为什么可以重名的问题
2022/03/22 MySQL