装饰器总结

前提

使用装饰器的前提在于Python提供的特性:

  1. 函数即对象,可以进行传递;
  2. 函数可以被定义在另外一个函数中;

可以通过一个例子来了解:

def get_animal(name='dog'):
def dog():
return 'this is a dog'
def cat():
return 'this is a cat'
# 返回函数对象
if name == 'dog':
return dog
elif name == 'cat':
return cat
else:
return 'other animal'
animal = get_animal('cat')
print(animal) # <function get_animal.<locals>.cat at 0x104b30d90>
print(animal())

注意:其返回的并不是调用函数,而是返回函数对象,只有在函数对象后面加上括号才表明要进行调用对象。

装饰器

装饰器就是可以在原来函数的基础上增加其它的功能,而不改变原函数本身。

如何写一个装饰器呢,下面给出一个基础的模版:

def my_decorator(a_function_to_decorate):
def wapper_function(*args, **kwargs):
print('Before the function runs')
a_function_to_decorate(*args, **kwargs)
print('After the function runs')
return wapper_function
@my_decorator
def stand_function():
print('stand function runs')
stand_function()

执行结果为:

Before the function runsstand function runsAfter the function runs


如果要求原函数的信息不变,那么可以使用functools.wraps,其本身也是一个装饰器,作用是将原函数的名称、模块、文档字符串等拷贝到装饰器里面的fun函数中,例子如下:

# "functools" 可以改变这点
import functools
def bar(func):
@functools.wraps(func)
def wrapper():
return func()
return wrapper

需要注意的问题是:

  1. 如果有多个装饰器的时候,则由里到外装饰,也就是按照距离函数的位置谁越近越就被装饰。
  2. 在装饰器的基础上还可以进行装饰,比如装饰装饰器的装饰器。

如果我们想要使用类来作为装饰器,那么被装饰的函数会作为类的参数被传入到类中。

比如写一个登陆检查的例子:

class LoginCheck:
def __init__(self, f):
self._f = f
def __call__(self, *args):
Status = check_function()
if Status is True:
return self._f(*args)
else:
return alt_function()
def check_function():
return True
def alt_function():
return('Sorry - this is the forced behaviour')
@LoginCheck
def display_members_page():
print('This is the members page')
display_members_page()

过程:它在访问相应的页面的时候,会进行登陆与否的检查,成功则返回相应的信息,反之则提示。


最后写一个题目,写一个decorator,在函数开始和结束时增加log,并且统计函数执行时间,保留原函数名:

import logging, time
def create_logger():
logger = logging.getLogger("example_logger")
logger.setLevel(logging.INFO)
# create the logging file handler
handler = logging.FileHandler(r"./test.log")
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
# add handler to logger object
logger.addHandler(handler)
return logger
def exception(logger):
def decorator(func):
def wrapper(*args, **kwargs):
start = time.time()
try:
logger.info('function runs')
res = func(*args, **kwargs)
print('the function used time: {}'.format(time.time()-start))
logger.info('function stops')
return res
except:
# log the exception
err = "There was an exception in "
err += func.__name__
logger.exception(err)
raise Exception
return wrapper
return decorator
logger = create_logger()
@exception(logger=logger)
def foo(name='foo_function'):
print('i am {}'.format(name))
return True
print(foo())

运行结果如下:

i am foo_functionthe function used time: 0.0008778572082519531True

logger中的结果如下:

2017-08-15 03:25:59,234 - example_logger - INFO - function runs2017-08-15 03:25:59,235 - example_logger - INFO - function stops

Python 装饰器总结的更多相关文章

  1. 关于python装饰器

    关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...

  2. python装饰器通俗易懂的解释!

    1.python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说 ...

  3. Python 装饰器学习

    Python装饰器学习(九步入门)   这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...

  4. python 装饰器修改调整函数参数

    简单记录一下利用python装饰器来调整函数的方法.现在有个需求:参数line范围为1-16,要求把9-16的范围转化为1-8,即9对应1,10对应2,...,16对应8. 下面是例子: def fo ...

  5. python 装饰器学习(decorator)

    最近看到有个装饰器的例子,没看懂, #!/usr/bin/python class decorator(object): def __init__(self,f): print "initi ...

  6. Python装饰器详解

    python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...

  7. 关于python装饰器(Decorators)最底层理解的一句话

    一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.h ...

  8. Python装饰器由浅入深

    装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...

  9. Python装饰器与面向切面编程

    今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数 ...

  10. python装饰器方法

    前几天向几位新同事介绍项目,被问起了@login_required的实现,我说这是django框架提供的装饰器方法,验证用户是否登录,只要这样用就行了,因为自己不熟,并没有做过多解释. 今天查看dja ...

随机推荐

  1. 关于XML(可扩展标记语言)的基础知识与写法

    XML(Extensible Markup Language) HTML:超文本标记语言,主要用来展示   XML:可扩展标记语言,用来做数据传输XML特点:1.树状结构,有且只有一个根2.标签名自定 ...

  2. MAC 相关操作解析

    MAC 相关操作解析 OS 显示桌面 f11 F1~F12 fn + F1~F12 撤销重做 command + z command + shift + z 图片预览 选择图片 空格 上下左右 svn ...

  3. Chrome控制台使用详解

    Chrome的开发者工具已经强大到没朋友的地步了,特别是其功能丰富界面友好的console,使用得当可以有如下功效: 更高「逼格」更快「开发调试」更强「进阶级的Frontender」 Bug无处遁形「 ...

  4. pyparsing:定制自己的解析器

    在工作中,经常需要解析不同类型的文件,常用的可能就是正则表达式了,简单点的,可能会使用awk.这里要推荐一种比较小众的方式,使用pyparsing来解析文件. pyparsing可以做些什么呢?主要可 ...

  5. 改变图像,运用match方法判断

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>菜鸟 ...

  6. [CF486D]有效集合-树形dp

    Problem 有效集合 题目大意 给出一棵树,求出这棵树的不同联通子节点集合的数量,这些集合必须满足最大权值点减最小权值点小于等于d. Solution 再一次树d乱搞. 因为数据范围贼小,所以我们 ...

  7. Java中的二进制及基本的位运算

    Java中的二进制及基本的位运算 二进制是计算技术中广泛采用的一种数制.二进制数据是用0和1两个数码来表示的数.它的基数为2,进位规则是"逢二进一",借位规则是"借一当二 ...

  8. UVa455 Periodic String 的wronganswer问题探讨,以及AC的新思路

    题目的意思是一个字符串有某个长度为k的字符串通过不断重复形成的,而k被称为该字符串的周期.而我们所要做的是找出该字符串的最小周期. input The first line is an integer ...

  9. Spring Boot 系列(三)属性配置&自定义属性配置

    在使用spring boot过程中,可以发现项目中只需要极少的配置就能完成相应的功能,这归功于spring boot中的模块化配置,在pom.xml中依赖的每个Starter都有默认配置,而这些默认配 ...

  10. 细说Handler

    今天来说说Android一个重要类吧:Handler (我写的博客风格不适合新手,因为我讨厌新手教学,我都是直奔主题,不交代前因后果) 大家都知道Handler的用法一般是线程间的通讯,当然,一个线程 ...