python装饰器入门探究

栏目: Python · 发布时间: 7年前

内容简介:装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。python的世界中,一切皆对象,把函数看做一个对象,一个可以拼接、编辑的对象。执行对象的方法是__ 对象()__观察下面的两个调用,他们的效果是一样的。

装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。python的世界中,一切皆对象,把函数看做一个对象,一个可以拼接、编辑的对象。执行对象的方法是__ 对象()__

装饰器只是 python 的语法糖

观察下面的两个调用,他们的效果是一样的。

#!/usr/bin/env python
#-*-coding:utf-8-*-

'''
@file: dec4.py
@time: 2018/12/13 17:15
'''
import functools

def register(func):        
    @functools.wraps(func)
    def warpper(*args,**kwargs):
        print("啦啦啦,这里装饰函数 %s"%func.__name__)
        result = func()      #这里就是真正的执行逻辑
        return result
    return warpper       # 返回包装后的函数

@register
def f1():
    print("使用@语法的装饰器 %s"%f1.__name__)


def f2():
    print("没@语法的装饰器 %s" % f2.__name__)

if __name__ == '__main__':
    f1()
    register(f2)()
    #或者
    # f_ = register(f2)
    # f_()
复制代码
python装饰器入门探究

装饰器启动装饰的时机

1、文件导入时装饰器已经启动对函数的装饰。

装饰器的一个关键特性是,它们在被装饰的函数定义之后立即运行。 这通常是在导入时(即 Python 加载模块时)。-- cookbook

创建文件 dec1.py

# dec1.py

registry = []  # 存放注册函数

def register(func):
    print('装饰器入列表(%s)' % func.__name__)
    registry.append(func)
    return func

@register
def f1():
    print('执行 %s'%f1.__name__)

@register
def f2():
    print('执行 %s' % f2.__name__)
复制代码

创建文件 dec2.py

# dec2.py
from 你的目录 import dec1
复制代码

执行文件 dec2.py 输出如下:

python装饰器入门探究

装饰器返回的结果

1、返回目标函数。 2、返回目标函数的结果。

以上 register的用法适用于对函数进行预处理的场景,例如flask框架的路由注册,在flask app启动时将所有的函数收集起来,与注册的路径进行一一对应,但是函数运行时跟原函数没有任何区别,因为装饰器返回的还是目标函数。假如我们需要在函数运行时进行日志的输出,则需要将函数进行一层封装,即将目标函数包装成另一个函数,这时返回的是另一个函数,只是包装后的函数可以进行额外的操作。

以下是两个装饰器的写法,注意区别。

import functools
def register1(func):      #在文件引入时返回目标函数的装饰器
    #这里进行一些函数预处理的操作,例如将函数名字收集进一个列表
    #list.append(func.__name__)
    return func

def register2(func):     #在函数运行时返回函数的装饰器
    @functools.wraps(func)
    def warpper(*args,**kwargs):
        print("函数没有执行 %s"%func.__name__)
        result = func      #这里就是真正的执行逻辑      #注意-----这里没有执行函数
        return result
    return warpper       # 返回包装后的函数


def register3(func):     #返回目标函数结果的装饰器
    @functools.wraps(func)
    def warpper(*args,**kwargs):

        print("函数开始执行 %s"%func.__name__)
        result = func()      #这里就是真正的执行逻辑
        return result
    return warpper       # 返回包装后的函数

@register1
def f1():
    print("执行函数 %s"%f1.__name__)

@register2
def f2():
    print("执行函数 %s"%f2.__name__)

@register3
def f3():
    print("执行函数 %s"%f3.__name__)


if __name__ == '__main__':
    f1()
    f2()
    f3()
复制代码

执行结果:

python装饰器入门探究

这时添加代码:

if __name__ == '__main__':
    f1()
    f2()
    f_ = f2()
    print("开始真正执行f2函数啦")
    f_()
    f3()
复制代码

执行结果:

python装饰器入门探究

装饰函数的属性保持

1、使用@functools.wraps

你会发现下面的代码中,如果wrapper函数没有使用__@functools.wraps装饰__的话,f1.__name__返回的是wrapper函数的名字,这是因为我们返回的函数已经是wrapper这个函数,所以__name__属性也就不是原来函数的了,__@functools.wraps装饰器__的作用就是将目标函数的属性例如__name__等原封不动转移给包装好的函数。

#!/usr/bin/env python
#-*-coding:utf-8-*-

'''
@file: dec4.py
@time: 2018/12/13 17:15
'''
import functools

def register(func):     #返回目标函数结果的装饰器

    def warpper(*args,**kwargs):
        result = func()      #这里就是真正的执行逻辑
        return result
    return warpper       # 返回包装后的函数

def register2(func):     #返回目标函数结果的装饰器
    @functools.wraps(func)
    def warpper(*args,**kwargs):
       
        result = func()      #这里就是真正的执行逻辑
        return result
    return warpper       # 返回包装后的函数

@register
def f1():
    print("函数名为 %s"%f1.__name__)

@register2
def f2():
    print("函数名为 %s" % f2.__name__)


if __name__ == '__main__':
    f1()
    f2()
    #或者
    #f_ = register(f2)
    #f_()
复制代码

带参数的装饰器

1、外层嵌套一层函数传参,返回一个装饰器。

装饰器也是一个对象,只要使用一个函数封装装饰器,返回目标装饰器即可,这时就可以通过外层的函数传进参数。

#!/usr/bin/env python
# -*-coding:utf-8-*-

'''
@author: 黄伟文
@email: huangweiwen@wtoip.com
@file: dec5.py
@time: 2018/12/13 18:13
'''
import functools


def dec_arg(arg=None):

    def register(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print('传进的参数为 %s' % arg)
            return func(*args, **kwargs)
        return wrapper
    return register  #这是装饰器

@dec_arg(arg='aaaa')
def f1():
    print("执行 %s"%f1.__name__)

def f2():
    print("执行 %s" % f2.__name__)


if __name__ == '__main__':
    f1()

    f2_ = dec_arg(arg='bbbb')(f2)
    f2_()

    dec_arg(arg='cccc')(f2)()
复制代码
python装饰器入门探究

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

500 Lines or Less

500 Lines or Less

Amy Brown、Michael DiBernardo / 2016-6-28 / USD 35.00

This book provides you with the chance to study how 26 experienced programmers think when they are building something new. The programs you will read about in this book were all written from scratch t......一起来看看 《500 Lines or Less》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

SHA 加密
SHA 加密

SHA 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具