Python学习札记(二十六) 函数式编程7 修饰器
修饰器
NOTE
1.函数对象有一个__name__属性,可以拿到函数的名字:
#!/usr/bin/env python3
def now():
print('2017/2/19')
def main():
f = now
f()
print(now.__name__)
print(f.__name__)
if __name__ == '__main__':
main()
sh-3.2# ./decorator1.py
2017/2/19
now
now
2.增强now函数的功能,又不想重新对now函数进行定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
本质上,装饰器就是一个返回函数的高阶函数:
#!/usr/bin/env python3
def log(func):
def wrapper():
print('call %s():' % func.__name__)
return func()
return wrapper
@log
def now():
print('2017/2/19')
def main():
f = now
f()
print(now.__name__)
print(f.__name__)
if __name__ == '__main__':
main()
sh-3.2# ./decorator1.py
call now():
2017/2/19
wrapper
wrapper
把@log放到now()函数的定义处,相当于执行了语句:
now = log(now)
由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。
now -> now()
=>
now -> wrapper()
把函数名看成指向函数的指针变量就好了。
3.将wrapper()函数的参数定义修改为(*args, **kw),使wrapper()函数可以接受任意参数的调用。
4.如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。
eg.使用Flask web框架的时候,需要传入参数(路径)制定路由。
@app.route('/')
def index()
return '<h1>Hello</h1>'
这种传入参数的实现是三个函数的嵌套:
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s()' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('wasdns')
def now():
print('2017/2/19')
wasdns now()
2017/2/19
wrapper
wrapper
@log('wasdns'):
now = log('wasdns')(now)
首先执行log('wasdns'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数。
一层一层解开。
5.函数也是Object,它有__name__等属性,但是在上面折腾之后,它的__name__属性变为:
wrapper
避免有些依赖函数签名的代码执行出错 => 需要把原始函数的__name__等属性复制到wrapper()函数中 => 调用Python内置的functools.wraps。
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
sh-3.2# ./decorator1.py
call now():
2017/2/19
now
now
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s()' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
sh-3.2# ./decorator2.py
wasdns now()
2017/2/19
now
now
加在最里层的函数首部(最后返回的是最里层的函数),修改其属性就达到了我们的目的。
decorator可以增强函数的功能,定义起来虽然有点复杂,但使用起来非常灵活和方便。
Practice
请编写一个decorator,能在函数调用的前后打印出'begin call'和'end call'的日志。
#!/usr/bin/env python3
import functools
def log1(func):
print('begin call')
func()
def wrapper(*args, **kw):
print('end call')
return wrapper
@log1
def func():
print('Hey Girl')
def main():
func()
if __name__ == '__main__':
main()
sh-3.2# ./decorator3.py
begin call
Hey Girl
end call
再思考一下能否写出一个@log的decorator,使它既支持:
@log
def f():
pass
又支持:
@log('execute')
def f():
pass
2017/2/19
Python学习札记(二十六) 函数式编程7 修饰器的更多相关文章
- Python学习札记(二十五) 函数式编程6 匿名函数
参考:匿名函数 NOTE 1.Python对匿名函数提供了有限的支持. eg. #!/usr/bin/env python3 def main(): lis = list(map(lambda x: ...
- Python学习札记(二十四) 函数式编程5 返回函数
参考:返回函数 NOTE 1.高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回. eg.求和函数 #!/usr/bin/env python3 def calsums(*args): a ...
- Python学习札记(三十六) 面向对象编程 Object Oriented Program 7 __slots__
参考:slots NOTE 1.动态语言灵活绑定属性及方法. #!/usr/bin/env python3 class MyClass(object): def __init__(self): pas ...
- Python学习札记(二十) 函数式编程1 介绍 高阶函数介绍
参考: 函数式编程 高阶函数 Note A.函数式编程(Functional Programming)介绍 1.函数是Python内建支持的一种封装,我们通过一层一层的函数调用把复杂任务分解成简单的任 ...
- Python学习札记(二十二) 函数式编程3 filter & SyntaxError: unexpected EOF while parsing
参考: filter Problem SyntaxError: unexpected EOF while parsing 遇到该语法错误,一般是由于 括号不匹配 问题. Note 1.filter 用 ...
- Python学习(二十六)—— Django基础一
转载自:http://www.cnblogs.com/liwenzhou/p/8258992.html 一.Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的 ...
- Python学习札记(三十九) 面向对象编程 Object Oriented Program 10
参考:使用枚举类 NOTE #!/usr/bin/env python3 from enum import Enum def main(): Mouth = Enum('Mouth', ('Jan', ...
- Python学习札记(三十八) 面向对象编程 Object Oriented Program 9
参考:多重继承 NOTE #!/usr/bin/env python3 class Animal(object): def __init__(self, name): self.name = name ...
- Python学习札记(三十五) 面向对象编程 Object Oriented Program 6
参考:实例属性和类属性 NOTE Python是动态语言,根据类创建的实例可以任意绑定属性. class Student(object): def __init__(self, name): self ...
随机推荐
- 详解Javascript中prototype属性
转自:https://www.jb51.net/article/91826.htm 在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Jav ...
- SQL中distinct的用法(转载)
1.作用于单列 2.作用于多列 3.COUNT统计 4.distinct必须放在开头 5.其他 在表中,可能会包含重复值.这并不成问题,不过,有时您也许希望仅仅列出不同(distinct)的值.关键词 ...
- wireshark, loopback
swapondd if=/dev/zero of=/data/mnt/swap bs=1024 count=8024000 sudo apt-get install wireshark sudo gr ...
- Faster R-CNN论文详解 - CSDN博客
废话不多说,上车吧,少年 paper链接:Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks ...
- python三层架构
conf/setting(配置文件) 一般是对utility进行相关设置 index(主文件) main函数触发某个对象的业务逻辑方法 model(数据库) admin 是对数据库的操 ...
- django2.0集成xadmin0.6报错集锦
1.django2.0把from django.core.urlresolvers修改成了django.urls 报错如下: 1 2 3 File "D:\Envs\django-xad ...
- OCR技术浅探:Python示例(5)
文件说明: 1. image.py——图像处理函数,主要是特征提取: 2. model_training.py——训练CNN单字识别模型(需要较高性能的服务器,最好有GPU加速,否则真是慢得要死): ...
- 江苏新美星智能物流无人叉车AGV
新美星一家全球领先的液体包装解决方案供应商,高附加值的产品应用于食品饮料等行业,为液体食品和自动化系统提供完整解决方案.新美星,于CBST2017展会首次亮相了能够从仓库或工厂的某个地方把材料.托盘和 ...
- PhotoSwipe中文API(四)
在幻灯片自定义HTML内容 为了使PhotoSwipe显示HTML内容的幻灯片,你需要在幻灯片对象定义html属性.它应该包含HTML字符串或DOM元素对象. var items = [ // sli ...
- controller中两个方法之间共享一个变量LinkedHashMap
1:引用传递,创建一个变量,给两个线程都传递进去. 2:静态修饰 static 通过该修饰符说明,该变量只有一份, 所有线程共用一份. 例如下面的htmlidMap通过static变量修饰, up ...