一、实现装饰器的预备知识

装饰器 = 高阶函数 + 函数嵌套 + 闭包

1、高价函数定义:

1.函数接收的参数是一个函数名
    2.函数的返回值是一个函数名
    3.满足上述条件任意一个,都可称之为高阶函数

例1:铺垫

 import time
#例1
def fn():
print('这是被调用函数')
time.sleep(2) def test(func):
print('高阶函数将要开始运行')
start_time = time.time()
func()
end_time = time.time()
print('被调用函数的运行时间%s'%(end_time - start_time)) test(fn)

例2

 #例2
import time
def fn():
print('这是被调用函数')
time.sleep(2)
def test(func):
print('正在执行高阶函数')
return func
#第一种调用
f = test(fn)
print(f)
f() ## 第二种调用,升级版 :将调用函数test(func)的返回值赋值给一个与被调用函数fn()同名的变量fn,最后实现的效果就是
#(1)不改变被调用函数fn()的源代码
#(2) 不改变被调用函数fn()的调用方式
fn = test(fn)
print(fn)
fn()
 正在执行高阶函数
<function fn at 0x0000017065C999D8>
这是被调用函数
正在执行高阶函数
<function fn at 0x0000017065C999D8>
这是被调用函数

升级版 :将调用函数test(func)的返回值赋值给一个与被调用函数fn()同名的变量fn,最后实现的效果就是
(1)不改变被调用函数fn()的源代码
(2) 不改变被调用函数fn()的调用方式

例3  这种情况出现的结果是 多运行了一行

 # 例3
import time
def fn():
print('这是被调用函数')
time.sleep(2) def test(func):
print('开始执行调用函数')
start_time = time.time()
func()
end_time = time.time()
return func # 这种情况出现的结果是 多运行了一行 fn = test(fn)
fn()
 开始执行调用函数
这是被调用函数
这是被调用函数

例4

 #例4
def fn():
print('这是被调用函数')
def test(func):
print('正在执行高阶函数')
res = func()
print('被调用函数执行完毕')
return res fn = test(fn)
# fn() # 报错 :TypeError: 'NoneType' object is not callable
 正在执行高阶函数
这是被调用函数
被调用函数执行完毕
即使赋了一个值,也还是解决不了多打印一行的结果。所以单层函数解决不了这个问题

高阶函数总结:
1、函数接收的参数是一个函数名
    作用:在不修改函数源代码的前提下,为函数添加新功能。
    不足:会改变函数的调用方式。
2、函数的返回值是一个函数名:
    作用:不修改函数的调用方式
    不足:不能添加新功能。

二、嵌套函数

定义:

 def father(name):
print('%s is from father'%name)
def son():
print('I am BeiJing,My fahter is %s'%name)
def grandson():
print('I am HaiDian,My grandfather is %s'%name)
grandson()
son()
# print(locals()) father('china')
 china is from father
I am BeiJing,My fahter is china
I am HaiDian,My grandfather is china

详解在我的另外一篇博客里面:http://www.cnblogs.com/jianguo221/p/8984618.html

三、实现装饰器(步骤进化)(重点中的重点)

 #进化版############################################################3
import time
def outer(func):
def inner():
print('开始运行被测试函数')
start_time = time.time()
func()
end_time = time.time()
print('被测试函数的运行时间是:%s'%(start_time - end_time))
return inner def test():
print('正在运行这个测试函数')
time.sleep(2)
# 慢慢实现装饰器
#第一种调用方式
f = outer(test) #这条语句返回的就是inner的地址,即函数体
f() #第二种调用方式
inner = outer(test) ##这条语句返回的就是inner的地址,即函数体
inner()
#由于第二种调用方式 和 第一种调用方式实现的效果是一样的。所以就满足了 装饰器的两个条件:
#(1)不改变被调用函数test()的源代码
#(2) 不改变被调用函数test()的调用方式
#继续过度:由于第二种方式满足了装饰器调用的两个条件,就可以用 装饰器的一个 语法糖 形式来替换第二种形式,
#以便实现简便操作 , 即加一个 @outer .如下面的例子
#加语法糖
#终极版###################################
import time
def outer(func):
def inner():
print('开始运行被测试函数')
start_time = time.time()
func()
end_time = time.time()
print('被测试函数的运行时间是:%s'%(start_time - end_time))
return inner
@outer
def test():
print('正在运行这个测试函数')
time.sleep(2) #加了语法糖后,调用方式就简单很多,只需要这样写就好了。语法糖 @outer 就等价于 test =outer(test)
test()

运行结果:

 开始运行被测试函数
正在运行这个测试函数
被测试函数的运行时间是:-2.000378370285034
开始运行被测试函数
正在运行这个测试函数
被测试函数的运行时间是:-2.0004947185516357
开始运行被测试函数
正在运行这个测试函数
被测试函数的运行时间是:-2.0002481937408447

十九、python沉淀之路--装饰器的更多相关文章

  1. Python修炼之路-装饰器、生成器、迭代器

    装饰器 本质:是函数,用来装饰其他函数,也就是为其他函数添加附加功能. 使用情景 1.不能修改被装饰的函数的源代码:        2.不能修改被装饰的函数的调用方式. 在这两种条件下,为函数添加附加 ...

  2. Python学习之路——装饰器

    开放封闭原则:不改变调用方式与源代码上增加功能 ''' 1.不能修改被装饰对象(函数)的源代码(封闭) 2.不能更改被修饰对象(函数)的调用方式,且能达到增加功能的效果(开放) ''' 装饰器 # 把 ...

  3. 十、python沉淀之路--高阶函数初识

    一.高阶函数:分两种:一种是返回值中包含函数体:另一种是把一个函数体当作了参数传给了另一个函数 1.返回值中包含函数体 例1. def test(): print('这是一个测试') return t ...

  4. Python中利用函数装饰器实现备忘功能

    Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下   " ...

  5. python函数与方法装饰器

    之前用python简单写了一下斐波那契数列的递归实现(如下),发现运行速度很慢. def fib_direct(n): assert n > 0, 'invalid n' if n < 3 ...

  6. guxh的python笔记三:装饰器

    1,函数作用域 这种情况可以顺利执行: total = 0 def run(): print(total) 这种情况会报错: total = 0 def run(): print(total) tot ...

  7. 十九. Python基础(19)--异常

    十九. Python基础(19)--异常 1 ● 捕获异常 if VS异常处理: if是预防异常出现, 异常处理是处理异常出现 异常处理一般格式: try:     <............. ...

  8. python设计模式之内置装饰器使用(四)

    前言 python内部有许多内建装饰器,它们都有特别的功能,下面对其归纳一下. 系列文章 python设计模式之单例模式(一) python设计模式之常用创建模式总结(二) python设计模式之装饰 ...

  9. python 3.x 的装饰器笔记

    今天学到了python的装饰器,感觉这个东西还是稍微有些复杂,所以记录下来,方便以后的查找.虽然标题是python 3.x的装饰器,但是我也没有怎么用过python 2.x,感觉上应该是和python ...

随机推荐

  1. 使用Angularjs开发Web App 视频课程 --麦子学院课程

    前往搓这里: http://www.maiziedu.com/group/common/course/3271/ 查看课程搓这里:http://www.maiziedu.com/course/web/ ...

  2. 黑苹果Yosemite 10.10.1懒人版完美安装及简单驱动设置

    1.硬件概要 CPU: 英特尔 Xeon E3-1230 V2 (四核)主板: 技嘉 H77-DS3H (Intel H77 (Panther Point Base))内存: 8 GBytes显卡: ...

  3. 详细解读ARM寄存器之CPSR【转】

    本文转载自:https://blog.csdn.net/david_luyang/article/details/6276533 详细解读ARM寄存器之CPSR 整理人:卢阳 QQ:820927872 ...

  4. sublime text3配置ctrl+鼠标左键进行函数跳转【转】

    本文转载自:https://blog.csdn.net/shangdibaozi/article/details/77503426 点击Preferences->Browse Packages进 ...

  5. lamp架构之升级php版本

    当你看到这篇文章的时候 YHSPY.COM 服务器上的PHP版本已经从 5.4.27 升级到了 7.0.4,这是一个重大的飞跃.一路升级遇到了很多问题.官方声称PHP7最大的升级就是在语言性能上的提升 ...

  6. 解决hive交互模式退格键乱码

    在hive的交互模式下,输入退格.方向键等,出现乱码,可以通过如下方法解决: 1.修改bashrc文件: vi ~/.bashrc 在文件最后添加一行: stty erase ^H. 2.使修改生效: ...

  7. scala学习手记7 - 运算符重载

    从语法上来说scala是没有运算符的.之前的一节里也曾提到过scala的运算符实际上是方法名,如1 + 2实际上就是1.+(2).我们可以将之视为运算符,是因为scala的一个特性:如果方法的参数小于 ...

  8. MFC--根据串口采集的数据借助GDI绘制曲线

    根据采集到的数据绘制曲线 在串口编程中会涉及到这样一个问题,就是将采集到的数据以曲线的形式展示出来,大家自然而然会想到采用方便快捷的控件进行编程.编程周期短,完成任务快,但是真实情况来看,控件会实现很 ...

  9. C++(十五) — sizeof 运算符

    1.基本数据类型 sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小. sizeof 运算符可用于获取类.结构.共用体和其他用户自定义数据类型的大小. 使用 sizeo ...

  10. 关于一些对location认识的误区(转)

    转自:http://www.cnblogs.com/lidabo/p/4169396.html 1. location 的匹配顺序是“先匹配正则,再匹配普通”. 矫正: location 的匹配顺序其 ...