Python进阶之装饰器
函数也是对象
要理解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()
fun_test所指向的函数的引用传递给decorator()函数decorator()函数中定义了wrap()子函数,这个子函数会调用通过func引用传递进来的fun_test()函数,并在调用函数的前后做了一些其他的事情decorator()函数返回内部定义的wrap()函数引用fun_test接收decorator()返回的函数引用,从而指向了一个新的函数对象- 通过
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进阶之装饰器的更多相关文章
- python进阶04 装饰器、描述器、常用内置装饰器
python进阶04 装饰器.描述器.常用内置装饰器 一.装饰器 作用:能够给现有的函数增加功能 如何给一个现有的函数增加执行计数的功能 首先用类来添加新功能 def fun(): #首先我们定义一个 ...
- Python进阶(六)----装饰器
Python进阶(六)----装饰器 一丶开放封闭原则 开放原则: 增加一些额外的新功能 封闭原则: 不改变源码.以及调用方式 二丶初识装饰器 装饰器: 也可称装饰器函数,诠释开放封闭原则 ...
- Python进阶: Decorator 装饰器你太美
函数 -> 装饰器 函数的4个核心概念 1.函数可以赋与变量 def func(message): print('Got a message: {}'.format(message)) send ...
- python进阶(三)~~~装饰器和闭包
一.闭包 满足条件: 1. 函数内嵌套一个函数: 2.外层函数的返回值是内层函数的函数名: 3.内层嵌套函数对外部作用域有一个非全局变量的引用: def func(): print("=== ...
- [Python进阶]002.装饰器(1)
装饰器(1) 介绍 HelloWorld 需求 使用函数式编程 加入装饰器 解析 介绍 Python的装饰器叫Decorator,就是对一个模块做装饰. 作用: 为已存在的对象添加额外功能. 与Jav ...
- python进阶:装饰器
1.闭包 简单理解:闭包就是多层函数的嵌套,外层函数的返回值是内层函数的引用. def out_func(n): num = 100 def in_fucn(*args,**kwargs): # no ...
- Python进阶(装饰器)
from datetime import datetime def log(func):#func表示装饰器作用于的函数 def wrapper(*args,**kw):#wrapper返回装饰器作用 ...
- 简单说明Python中的装饰器的用法
简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下 装饰器对与 ...
- 【Python】【装饰器】
Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...
随机推荐
- 用js实现图片的无缝滚动效果
实现图片的无缝滚动就是要让你的图片集在一定时间里自动切换,那就需要js里的定时器来控制时间. js中关于定时器的方法有两种:setTimeout和setInterval.它们接收的参数是一样的,第一个 ...
- Linux 和 Windows 下实现多进程的方式以及管道操作
一.多进程 1.windows 多进程 使用 #include<windows.h> 下面的 BOOL CreateProcess( LPCWSTR pszImageName, LPCWS ...
- file_get_contents和curl对于post方式的解决办法
post方式解决办法 其实很简单,我们只要仔细看看就知道了... file_get_contents: $content=$_POST['content'];$access_token=$_POST[ ...
- iOS 中的单例设计模式
单例设计模式:在它的核心结构中只包含一个被称为单例类的特殊类.例如文件管理中的NSUserDefault,应用程序中的UIApplication,整个应用程序就这一个单例类,负责应用程序的一些操作,单 ...
- 自适应滤波:最小均方误差滤波器(LMS、NLMS)
作者:桂. 时间:2017-04-02 08:08:31 链接:http://www.cnblogs.com/xingshansi/p/6658203.html 声明:欢迎被转载,不过记得注明出处哦 ...
- npm命令点滴记录
关于-save-dve后缀命令: 当你为你的模块安装一个依赖模块时,正常情况下你得先安装他们(在模块根目录下npm install module-name),然后连同版本号手动将他们添加到模块配置文件 ...
- .net mvc------下拉列表DropDownList控件------绑定数据
下拉列表 以性别为例 绑定可以了,可以显示了,但有些地方就能传值,有些地方就会出错提示,如有大神请指教.... 错误如下: 具有键"sex"的 ViewData 项属于类型&quo ...
- shiro基础学习(四)—shiro与项目整合
一.认证 1.配置web.xml 2.配置applicationContext.xml 在applicationContext.xml中配置一个bean,ID和上面的过滤器的名称一致. ...
- SIM9001GSM模块教程
博主最近在做一个项目,用到了GSM模块,博主不是什么单片机大神,只是感觉某宝附带的资料太水,所以上传一些自己写的程序和经验,供需要的人参考 1,拨打电话 /********************** ...
- --save 和 --save-dev的区别
--save是对生产环境所需依赖的声明(开发应用中使用的框架,库,比如jquery,bootstrap等) --save-dev是对开发环境所需依赖的声明(构建工具,测试工具,比如babel,gulp ...