什么是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 相关文章推荐
windows下python模拟鼠标点击和键盘输示例
Feb 28 Python
python实现随机密码字典生成器示例
Apr 09 Python
python使用xauth方式登录饭否网然后发消息
Apr 11 Python
从零学python系列之数据处理编程实例(二)
May 22 Python
基于python的七种经典排序算法(推荐)
Dec 08 Python
python自动化脚本安装指定版本python环境详解
Sep 14 Python
Python生成任意范围任意精度的随机数方法
Apr 09 Python
对Python中range()函数和list的比较
Apr 19 Python
python multiprocessing模块用法及原理介绍
Aug 20 Python
Python3+Requests+Excel完整接口自动化测试框架的实现
Oct 11 Python
Python爬取YY评级分数并保存数据实现过程解析
Jun 01 Python
python游戏开发之pygame实现接球小游戏
Apr 22 Python
Python经常使用的一些内置函数
python处理json数据文件
Python几种酷炫的进度条的方式
Python通过loop.run_in_executor执行同步代码 同步变为异步
Python Pandas解析读写 CSV 文件
宝塔更新Python及Flask项目的部署
python模板入门教程之flask Jinja
You might like
点评山进PR-D3L三波段收音机
2021/03/02 无线电
Apache, PHP在Windows 9x/NT下的安装与配置 (二)
2006/10/09 PHP
PHP 加密与解密的斗争
2009/04/17 PHP
php中选择什么接口(mysql、mysqli)访问mysql
2013/02/06 PHP
Some tips of wmi scripting in jscript (1)
2007/04/03 Javascript
浅析JQuery UI Dialog的样式设置问题
2013/12/18 Javascript
JavaScript中document对象使用详解
2015/01/06 Javascript
JavaScript组件开发完整示例
2015/12/15 Javascript
用jquery获取自定义的标签属性的值简单实例
2016/09/17 Javascript
jQuery ajax的功能实现方法详解
2017/01/06 Javascript
cropper js基于vue的图片裁剪上传功能的实现代码
2018/03/01 Javascript
解决JS表单验证只有第一个IF起作用的问题
2018/12/04 Javascript
js判断鼠标移入移出方向的方法
2020/06/24 Javascript
python通过socket查询whois的方法
2015/07/18 Python
分享Python文本生成二维码实例
2016/01/06 Python
python WindowsError的错误代码详解
2017/07/23 Python
分享一下如何编写高效且优雅的 Python 代码
2017/09/07 Python
python深度优先搜索和广度优先搜索
2018/02/07 Python
深入分析python数据挖掘 Json结构分析
2018/04/21 Python
小程序canvas中文字设置居中锚点
2019/04/16 HTML / CSS
遮罩层 + Iframe实现界面自动显示的示例代码
2020/04/26 HTML / CSS
应届生法律顾问求职信
2013/11/19 职场文书
大学四年的个人自我评价
2014/01/14 职场文书
教师辞职报告范文
2014/01/20 职场文书
教育技术职业规划范文
2014/03/04 职场文书
学生会副主席竞聘书
2014/03/31 职场文书
市场营销专业自荐书
2014/06/10 职场文书
2014教师研修学习体会
2014/07/08 职场文书
乡镇挂职心得体会
2014/09/04 职场文书
民主生活会对照检查材料(统计局)
2014/09/21 职场文书
护林员个人总结
2015/03/04 职场文书
小学教师师德师风承诺书
2015/04/28 职场文书
小学生节水倡议书
2015/04/29 职场文书
2016年禁毒宣传活动总结
2016/04/05 职场文书
慰问信(范文3篇)
2019/10/23 职场文书
SpringBoot集成Druid连接池连接MySQL8.0.11
2021/07/02 Java/Android