python装饰器入门探究

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

内容简介:装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。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装饰器入门探究

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

查看所有标签

猜你喜欢:

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

从问题到程序

从问题到程序

裘宗燕 / 机械工业出版社 / 2005-9-1 / 36.00元

本书以C作为讨论程序设计的语言,讨论了基本程序设计的各方面问题。书中给出程序实例时没有采用常见的提出问题,给出解答,再加些解释的简单三步形式,而是增加了许多问题的分析和讨论,以帮助读者认识程序设计过程的实质,理解从问题到程序的思考过程。书中还尽可能详尽地解释了许多与C语言和程序设计有关的问题。 本书适合作为高等院校计算机及相关专业的教材,也可供其他学习C程序设计语言的读者阅读。一起来看看 《从问题到程序》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具