python cookbook 学习系列(一) python中的装饰器

简介

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能,我们也称之为AOP(面向切面编程)

原理

实现装饰器的最主要的原因是python中一切皆为对象,我们会把方法看做一个对象包装起来

实现

首相,我们先来看一个简单的例子,有一个add方法:

def add(x, y):
    print(‘result is {}‘.format(x + y))

现在有一个新的需求,我们想在这个方法执行完之后print一句话证明他执行成功了,同样我们又不想修改这个add方法,那我们可以新建一个方法:

def printres(func):
    func()
    print(‘Done‘)
printres(add)

那这样是ok的。但是这样的话,我们每次都要将一个函数作为参数传递给printres函数。而且这种方式已经破坏了原有的代码逻辑结构,之前执行业务逻辑时,执行运行add(),但是现在不得不改成printres(add)。那么有没有更好的方式的呢?当然有,答案就是装饰器。我就直接贴代码:

# coding=utf-8
"""
学习装饰器 2016-08-20 by oldman
"""
from functools import wraps

"""
先来看一个简单的装饰器
"""

def decor1(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        func(*args, **kwargs)
        print(‘i am a decorate‘)

    return wrapper

@decor1
def add(x, y):
    print(‘result is {}‘.format(x + y))

# if __name__  =="__main__":
#     add(2,3)

"""
再来看一个带参数的装饰器
"""

def decor2(parm):
    """
    parm为装饰器用到的参数
    """

    def _decor2(func):  # func为被装饰的函数
        @wraps(func)
        def wrapper(*args, **kwargs):
            if parm:
                func(*args)
                print(‘I am true‘)
            else:
                print(‘sorry, false‘)

        return wrapper

    return _decor2

@decor2(True) # 这里装饰器的参数为True
def add1(x, y):
    print(‘result is {}‘.format(x + y))

if __name__ == ‘__main__‘:
    add1(2, 3)

注意到functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了,如果不在装饰器里使用@wrap的话,被装饰的函数的元信息会丢失。

总结

这是一个很好的解决方案,不得不感叹python的灵活,人生苦短,我用python。

源代码地址(Github)

参考文章:http://www.zhihu.com/question/26930016

学习交流群 :226704167

时间: 2025-01-20 02:26:41

python cookbook 学习系列(一) python中的装饰器的相关文章

Python爬虫学习系列教程

Python爬虫学习系列教程 大家好哈,我呢最近在学习Python爬虫,感觉非常有意思,真的让生活可以方便很多.学习过程中我把一些学习的笔记总结下来,还记录了一些自己实际写的一些小爬虫,在这里跟大家一同分享,希望对Python爬虫感兴趣的童鞋有帮助,如果有机会期待与大家的交流. Python版本:2.7 一.爬虫入门 1. Python爬虫入门一之综述 2. Python爬虫入门二之爬虫基础了解 3. Python爬虫入门三之Urllib库的基本使用 4. Python爬虫入门四之Urllib库

Comprehensive learning path – Data Science in Python深入学习路径-使用python数据中学习

http://blog.csdn.net/pipisorry/article/details/44245575 关于怎么学习python,并将python用于数据科学.数据分析.机器学习中的一篇非常好的文章 Comprehensive learning path – Data Science in Python 深度学习路径-用python进行数据学习 Journey from a Pythonnoob(新手) to a Kaggler on Python So, you want to bec

@修饰符--python中的装饰器

http://blog.csdn.net/shangzhihaohao/article/details/6928808 装饰器模式可以在不影响其他对象的情况下,以动态.透明的方式给单个对象添加职责,也能够处理那些可以撤销的职责.经常用于日志记录.性能测试等场合. 想象一下这个很常见的场景,你写了一个方法只提供给以登陆的用户访问(事实上我也是通过django的@login_required才了解到@修饰符的),你可以写以下代码: 这当然没什么问题,但是你又写了一个方法B,也要求只有登录用户可以访问

Python 中实现装饰器时使用 @functools.wraps 的理由

Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下--比如测试时--会导致一些问题.Python 通过 functool.wraps 为我们解决了这个问题:在编写装饰器时,在实现前加入 @functools.wraps(func) 可以保证装饰器不会对被装饰函数造成影响.比如,在 Flask 中,我们要自己重写 login_required 装饰器,但不想影响被装饰器装饰的方法,则 login_req

如何理解python中的装饰器, 这篇文章就够了!

1. python中的函数 理解裝飾器之前先要理解閉包, python中閉包的出現是因爲函數在python中也是一個對象, 也可以被引用, 然後調用, 比如 def log(): print('我是一些log信息') if __name__ == '__main__': print(type(log)) log_func = log log_func() 執行結果如下 <class 'function'> 我是一些log信息 可以看到log函數是一個對象, 可以被賦值給log_func, lo

Python自动化运维之6、函数装饰器

装饰器: 装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator),装饰器的功能非常强大.装饰器一般接受一个函数对象作为参数,以对其进行增强 装饰器本身是一个函数,用于装饰其他函数 功能:增强被装饰函数的功能 装饰器是一个闭包函数是嵌套函数,通过外层函数提供嵌套函数的环境 装饰器在权限控制,增加额外功能如日志,发送邮件用的比较多 装饰器知识准备一: >>> def f1(): ... print("hel

SpringMVC学习(十二)——SpringMVC中的拦截器

SpringMVC学习(十二)--SpringMVC中的拦截器 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.本文主要总结一下SpringMVC中拦截器是如何定义的,以及测试拦截器的执行情况和使用方法. SpringMVC中拦截器的定义和配置 SpringMVC中拦截器的定义 在SpringMVC中,定义拦截器要实现HandlerInterceptor接口,并实现该接口中提供的三个方法,如下: public class Inter

自己编写一个装饰器中的装饰器函数

看了"大道曙光"的<探究functools模块wraps装饰器的用途>的文章.基本上弄清了wraps的工作原理,为了检验一下自己理解的程度,于是动手写一个类似的 wraps函数,请大家指教. #!/usr/bin/env python # -*- coding: utf-8 -*- #filename : mywrapper.py #date: 2017-06-02 ''' wrapper function by my code.''' import functools i

IO中的装饰器模式

//可以进InputStream 类 区分为目的和方法两类 //一般直接子类,都是目的不同的(A类), // 如FileInputStream, #从文件中获得字节.// ByteArrayInputStream #包含一个内存缓冲区,字节从中取出.// ObjectInputStream #用来恢复被序列化的对象.// PipedInputStream #管道输入流,读取管道内容.多和PipedOutputStream一起用于多线程通信.// SequenceInputStream #是多种输