什么是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计算一个文件里字数的方法
Jun 15 Python
Python上传package到Pypi(代码简单)
Feb 06 Python
浅谈python中的数字类型与处理工具
Aug 02 Python
python: 自动安装缺失库文件的方法
Oct 22 Python
Python将string转换到float的实例方法
Jul 29 Python
python实现爬虫抓取小说功能示例【抓取金庸小说】
Aug 09 Python
利用python实现汉字转拼音的2种方法
Aug 12 Python
ipad上运行python的方法步骤
Oct 12 Python
django实现将后台model对象转换成json对象并传递给前端jquery
Mar 16 Python
Python脚本实现Zabbix多行日志监控过程解析
Aug 26 Python
Python OpenCV超详细讲解读取图像视频和网络摄像头
Apr 02 Python
Python中time标准库的使用教程
Apr 13 Python
Python经常使用的一些内置函数
python处理json数据文件
Python几种酷炫的进度条的方式
Python通过loop.run_in_executor执行同步代码 同步变为异步
Python Pandas解析读写 CSV 文件
宝塔更新Python及Flask项目的部署
python模板入门教程之flask Jinja
You might like
使用php实现下载生成某链接快捷方式的解决方法
2013/05/07 PHP
PHP 线程安全与非线程安全版本的区别深入解析
2013/08/06 PHP
Thinkphp5框架中引入Markdown编辑器操作示例
2020/06/03 PHP
JavaScript 在各个浏览器中执行的耐性
2009/04/06 Javascript
支持ie与FireFox的剪切板操作代码
2009/09/28 Javascript
Span元素的width属性无效果原因及解决方案
2010/01/15 Javascript
Jquery ThickBox插件使用心得(不建议使用)
2010/09/08 Javascript
JS对象转换为Jquery对象示例
2014/01/26 Javascript
七个很有意思的PHP函数
2014/05/12 Javascript
jQuery根据元素值删除数组元素的方法
2015/06/24 Javascript
基于KO+BootStrap+MVC实现的分页控件代码分享
2016/11/07 Javascript
使用travis-ci如何持续部署node.js应用详解
2017/07/30 Javascript
JS实现分页浏览横向图片(类轮播)实例代码
2017/11/06 Javascript
详解js的视频和音频采集
2018/08/09 Javascript
jQuery实现简单的Ajax调用功能示例
2019/02/15 jQuery
vue eslint简要配置教程详解
2019/07/26 Javascript
Vue 禁用浏览器的前进后退操作
2020/09/04 Javascript
[01:04:48]VGJ.S vs TNC Supermajor 败者组 BO3 第一场 6.6
2018/06/07 DOTA
python中列表和元组的区别
2017/12/18 Python
Python实现的多进程和多线程功能示例
2018/05/29 Python
python ddt数据驱动最简实例代码
2019/02/22 Python
python 环境搭建 及python-3.4.4的下载和安装过程
2019/07/20 Python
pytorch中的卷积和池化计算方式详解
2020/01/03 Python
Python中的整除和取模实例
2020/06/03 Python
python如何编写类似nmap的扫描工具
2020/11/06 Python
Python修改DBF文件指定列
2020/12/19 Python
美国著名的婴儿学步鞋老品牌:Robeez
2016/08/20 全球购物
物流专业大学生职业生涯规划书范文
2014/01/15 职场文书
甜点店创业计划书
2014/01/27 职场文书
安全责任书范本
2014/04/15 职场文书
邮政竞聘演讲稿
2014/09/03 职场文书
党员个人剖析材料
2014/09/30 职场文书
2014年师德师风工作总结
2014/11/25 职场文书
党员自评材料范文
2014/12/17 职场文书
投资合作意向书范本
2015/05/08 职场文书
USB TYPE-C 或将成为所有智能手机充电标准
2022/04/21 数码科技