函数也是对象

要理解Python装饰器,首先要明白在Python中,函数也是一种对象,因此可以把定义函数时的函数名看作是函数对象的一个引用。既然是引用,因此可以将函数赋值给一个变量,也可以把函数作为一个参数传递或返回。同时,函数体中也可以再定义函数。

装饰器本质

可以通过编写一个纯函数的例子来还原装饰器所要做的事。

def decorator(func):

    def wrap():
print("Doing someting before executing func()")
func()
print("Doing someting after executing func()") return wrap def fun_test():
print("func") fun_test = decorator(fun_test)
fun_test() # Output:
# Doing someting before executing func()
# func
# Doing someting after executing func()
  1. fun_test所指向的函数的引用传递给decorator()函数
  2. decorator()函数中定义了wrap()子函数,这个子函数会调用通过func引用传递进来的fun_test()函数,并在调用函数的前后做了一些其他的事情
  3. decorator()函数返回内部定义的wrap()函数引用
  4. fun_test接收decorator()返回的函数引用,从而指向了一个新的函数对象
  5. 通过fun_test()调用新的函数执行wrap()函数的功能,从而完成了对fun_test()函数的前后装饰

Python中使用装饰器

在Python中可以通过@符号来方便的使用装饰器功能。

def decorator(func):

    def wrap():
print("Doing someting before executing func()")
func()
print("Doing someting after executing func()") return wrap @decorator
def fun_test():
print("func") fun_test() # Output:
# Doing someting before executing func()
# func
# Doing someting after executing func()

装饰的功能已经实现了,但是此时执行:

print(fun_test.__name__)

# Output:
# wrap

fun_test.__name__已经变成了wrap,这是应为wrap()函数已经重写了我们函数的名字和注释文档。此时可以通过functools.wraps来解决这个问题。wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

更规范的写法:

from functools import wraps

def decorator(func):
@wraps(func)
def wrap():
print("Doing someting before executing func()")
func()
print("Doing someting after executing func()") return wrap @decorator
def fun_test():
print("func") fun_test()
print(fun_test.__name__) # Output:
# Doing someting before executing func()
# func
# Doing someting after executing func()
# fun_test

带参数的装饰器

通过返回一个包裹函数的函数,可以模仿wraps装饰器,构造出一个带参数的装饰器。

from functools import wraps

def loginfo(info='info1'):
def loginfo_decorator(func):
@wraps(func)
def wrap_func(*args, **kwargs):
print(func.__name__ + ' was called')
print('info: %s' % info) return func(*args, **kwargs)
return wrap_func
return loginfo_decorator @loginfo()
def func1():
pass func1() # Output:
# func1 was called
# info: info1 @loginfo(info='info2')
def func2():
pass func2()
# Output:
# func2 was called
# info: info2

装饰器类

通过编写类的方法也可以实现装饰器,并让装饰器具备继承等面向对象中更实用的特性

首先编写一个装饰器基类:

from functools import wraps

class loginfo:
def __init__(self, info='info1'):
self.info = info def __call__(self, func):
@wrap
def wrap_func(*args, **kwargs):
print(func.__name__ + ' was called')
print('info: %s' % self.info) self.after() # 调用after方法,可以在子类中实现
return func(*args, **kwargs)
return wrap_func def after(self):
pass @loginfo(info='info2')
def func1():
pass # Output:
# func1 was called
# info: info1

再通过继承loginfo类,扩展装饰器的功能:

class loginfo_after(loginfo):
def __init__(self, info2='info2', *args, **kwargs):
self.info2 = info2
super(loginfo_after, self).__init__(*args, **kwargs) def after(self):
print('after: %s' % self.info2) @loginfo_after()
def func2():
pass func2() # Output:
# func2 was called
# info: info1
# after: info2

Python进阶之装饰器的更多相关文章

  1. python进阶04 装饰器、描述器、常用内置装饰器

    python进阶04 装饰器.描述器.常用内置装饰器 一.装饰器 作用:能够给现有的函数增加功能 如何给一个现有的函数增加执行计数的功能 首先用类来添加新功能 def fun(): #首先我们定义一个 ...

  2. Python进阶(六)----装饰器

    Python进阶(六)----装饰器 一丶开放封闭原则 开放原则: ​ 增加一些额外的新功能 封闭原则: ​ 不改变源码.以及调用方式 二丶初识装饰器 装饰器: ​ 也可称装饰器函数,诠释开放封闭原则 ...

  3. Python进阶: Decorator 装饰器你太美

    函数 -> 装饰器 函数的4个核心概念 1.函数可以赋与变量 def func(message): print('Got a message: {}'.format(message)) send ...

  4. python进阶(三)~~~装饰器和闭包

    一.闭包 满足条件: 1. 函数内嵌套一个函数: 2.外层函数的返回值是内层函数的函数名: 3.内层嵌套函数对外部作用域有一个非全局变量的引用: def func(): print("=== ...

  5. [Python进阶]002.装饰器(1)

    装饰器(1) 介绍 HelloWorld 需求 使用函数式编程 加入装饰器 解析 介绍 Python的装饰器叫Decorator,就是对一个模块做装饰. 作用: 为已存在的对象添加额外功能. 与Jav ...

  6. python进阶:装饰器

    1.闭包 简单理解:闭包就是多层函数的嵌套,外层函数的返回值是内层函数的引用. def out_func(n): num = 100 def in_fucn(*args,**kwargs): # no ...

  7. Python进阶(装饰器)

    from datetime import datetime def log(func):#func表示装饰器作用于的函数 def wrapper(*args,**kw):#wrapper返回装饰器作用 ...

  8. 简单说明Python中的装饰器的用法

    简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下   装饰器对与 ...

  9. 【Python】【装饰器】

    Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...

随机推荐

  1. iOS开发之单例模式

    1.概述 单例模式是一种常用的软件设计模式,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源. 如果希望系统中某个类的对象只能存在一个,单例模 ...

  2. Spring 框架原理

    [spring框架原理] Spring框架原理 [博主]高瑞林 [博客地址]http://www.cnblogs.com/grl214 写给读者的话 ------亲爱的读者感谢您对小编的支持,当我正值 ...

  3. CSS媒体查询适配范例

    /*orientation:portrait纵向*/ /*orientation:landscape横向*/ /*iPhone 4*/ @media only screen and (min-devi ...

  4. 简单实用的JQuery弹出层

    效果: 初始状态时滚动条是可以滚动的 弹出层出现之后:1.弹窗始终居于整个窗口的中间 2.滚动条不可滚动 实现代码: HTML代码: <div class="container&quo ...

  5. Canvas绘制一个大鱼喂小鱼的游戏

    Canvas是HTML5中的一部分,强大的API足以让我们绘制我们任意想绘制的东西.利用Canvas的基础学习以及JavaScript面向对象的思想绘制一个小游戏,下面是源码地址https://git ...

  6. yii2-验证规则,rules,判断条件

    yii2模型的验证规则,简单的使用我就不详细说了,想看的可以去看官网教程http://www.yiichina.com/doc/guide/2.0/structure-models#validatio ...

  7. Spring基础学习(二)—详解Bean(上)

         在Spring配置文件中,用户不但可以将String.int等字面值注入Bean中,还可以将集合.Map等类型注入Bean中,此外还可以注入配置文件中其他定义的Bean. 一.字面值     ...

  8. 基于MVC和Bootstrap的权限框架解决方案 二.添加增删改查按钮

    上一期我们已经搭建了框架并且加入了列表的显示, 本期我们来加入增删改查按钮 整体效果如下 HTML部分,在HTML中找到中意的按钮按查看元素,复制HTML代码放入工程中 <a class=&qu ...

  9. 基于WebForm和Bootstrap的权限框架解决方案 一.PQGRID的使用

    天天打游戏也不是个事,就写一套权限框架吧,我的要求是即漂亮美观大方上档次,又要实用易用接地气. 按理来说应该先设计数据库在来秀的,但是人生就是这么随意,先搭个框子吧, 这一篇的重点是pqgrid的介绍 ...

  10. C++ fstream 详解

    最近在写哈夫曼压缩,遇到了一个比较让人头疼的问题,那就是对文件的读写操作,尤其是以二进制的形式来读写,无奈C++Primer第五版上写的并不详细,很多让人困惑的地方没有涉及或者没有讲清楚.于是这几天我 ...