函数也是对象

要理解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. Map集合概述和特点

    A:Map集合概述和特点(Set底层依赖的是Map) 将键映射到值的对象 一个映射不能包含重复的键 每个键最多只能映射到一个值 B:Map接口和Collection接口的不同 Map是双列的(是双列集 ...

  2. java学习笔记 --- 面向对象3

    一.创建对象是做了些什么事情? 图解: 二.static关键字 (1)静态的意思.可以修饰成员变量和成员方法. (2)静态的特点: 1.静态是随着类的加载就加载了.也是随着类的消失而消失了. 2.静态 ...

  3. iOS开发之Segue

    Storyboard上每一根用来界面跳转的线,都是一个UIStoryboardSegue对象(简称Segue). 每一个Segue对象,都有3个属性: (1)唯一标识 @property (nonat ...

  4. CDMA sid, nid, bid 含义解释

    copyright@ celldb.cc SID 是系统识别码,每个地级市只有一个sid,是唯一的. NID是网络识别码,由各本地网管理,也就是由地级分公司分配.每个地级市可能有1到3个nid. BI ...

  5. 不使用回调函数的ajax请求实现(async和await简化回调函数嵌套)

    在常规的服务器端程序设计中, 比如说爬虫程序, 发送http请求的过程会使整个执行过程阻塞,直到http请求响应完成代码才会继续执行, 以php为例子 $url = "http://www. ...

  6. php写留言板

    简单的PHP留言板制作 做基础的留言板功能  需要三张表: 员工表,留言表,好友表 首先造一个登入页面: <form action="drcl.php" method=&qu ...

  7. QQ登陆接口

    这次做了一个QQ登陆接口---简单记录一下 遇到一大坑-----QQ互联里面添加应用的时候,是网站应用,配置回调地址一定要配置  准确,到指定回调页面 否则会出现问题的.

  8. Apache Storm 1.1.0 发布概览

    写在前面的话 本人长期关注数据挖掘与机器学习相关前沿研究.欢迎和我交流,私人微信:846731084 我自己测试了一下这个版本,总的来说更加稳定,新增的特性并没有一一测试,仅凭kafk-client来 ...

  9. iOS开发寻找最近公共view

    新技能 #pragma mark --寻找最近公共view + (NSArray *)superViews:(UIView *)view{ if (view==nil) { return @[]; } ...

  10. webService请求方式快速生成代码 (Postman)

    Postman 这个东西只能在外网下载,是Goole一个插件. 1.FQ到外网,这里就不具体介绍怎么FQ了 2.上到谷歌浏览器,找到更过工具--->扩张程序--->获取更多扩张程序 3.在 ...