什么是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 相关文章推荐
Python2.x和3.x下maketrans与translate函数使用上的不同
Apr 13 Python
python简单实现基于SSL的IRC bot实例
Jun 15 Python
使用Python OpenCV为CNN增加图像样本的实现
Jun 10 Python
10分钟用python搭建一个超好用的CMDB系统
Jul 17 Python
Python帮你识破双11的套路
Nov 11 Python
使用Python进行防病毒免杀解析
Dec 13 Python
基于python爬取有道翻译过程图解
Mar 31 Python
浅析Python的命名空间与作用域
Nov 25 Python
pytorch中的model=model.to(device)使用说明
May 24 Python
pytorch 权重weight 与 梯度grad 可视化操作
Jun 05 Python
Python+Matplotlib图像上指定坐标的位置添加文本标签与注释
Apr 11 Python
python​格式化字符串
Apr 20 Python
Python经常使用的一些内置函数
python处理json数据文件
Python几种酷炫的进度条的方式
Python通过loop.run_in_executor执行同步代码 同步变为异步
Python Pandas解析读写 CSV 文件
宝塔更新Python及Flask项目的部署
python模板入门教程之flask Jinja
You might like
php 输出双引号&quot;与单引号'的方法
2010/05/09 PHP
解析如何去掉CodeIgniter URL中的index.php
2013/06/25 PHP
ThinkPHP使用心得分享-分页类Page的用法
2014/05/15 PHP
php利用fsockopen GET/POST提交表单及上传文件
2017/05/22 PHP
如何将网页表格内容导入excel
2014/02/18 Javascript
js实现简洁的滑动门菜单(选项卡)效果代码
2015/09/04 Javascript
基于JavaScript实现图片点击弹出窗口而不是保存
2016/02/06 Javascript
js实现的在线调色板功能完整实例
2016/12/21 Javascript
AngularJS实现的输入框字数限制提醒功能示例
2017/10/26 Javascript
Vue.directive()的用法和实例详解
2018/03/04 Javascript
详解如何在vue-cli中使用vuex
2018/08/07 Javascript
vue-cli中vue本地实现跨域调试接口
2019/01/16 Javascript
js纯前端实现腾讯cos文件上传功能的示例代码
2019/05/14 Javascript
vue项目中将element-ui table表格写成组件的实现代码
2019/06/12 Javascript
微信小程序 子级页面返回父级并把子级参数带回父级实现方法
2019/08/22 Javascript
vuex实现购物车功能
2020/06/28 Javascript
js+canvas实现图片格式webp/png/jpeg在线转换
2020/08/22 Javascript
vue实现几秒后跳转新页面代码
2020/09/09 Javascript
openlayers 3实现车辆轨迹回放
2020/09/24 Javascript
vant中的toast层级改变操作
2020/11/04 Javascript
NestJs使用Mongoose对MongoDB操作的方法
2021/02/22 Javascript
python基于Tkinter库实现简单文本编辑器实例
2015/05/05 Python
Python多进程分块读取超大文件的方法
2016/04/13 Python
Pycharm设置界面全黑的方法
2018/05/23 Python
python使用参数对嵌套字典进行取值的方法
2019/04/26 Python
pandas.read_csv参数详解(小结)
2019/06/21 Python
Python FtpLib模块应用操作详解
2019/12/12 Python
HTML5是否真的可以取代Flash
2010/02/10 HTML / CSS
家用个人磨皮机:Trophy Skin
2017/03/30 全球购物
荷兰包包购物网站:The Little Green Bag
2018/03/17 全球购物
请解释在new与override的区别
2012/10/29 面试题
社会实践活动总结报告
2014/04/29 职场文书
师德承诺书
2015/01/20 职场文书
2016年暑假家长对孩子评语
2015/12/01 职场文书
DE1103使用报告
2022/04/05 无线电
MySQL事务操作的四大特性以及并发事务问题
2022/04/12 MySQL