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

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

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. jQuery可自动播放动画的焦点图

    在线演示 本地下载

  2. 饭卡管理系统学生E-R图

    - 2 - 1.1 可行性分析 1.1.1 项目背景 近年来学生食堂饭卡的使用给高校餐饮管理带来了一次革命, 从结算方式到账户管理, 从卫生便捷到数据统计等,不仅给就餐者带来了方便,也使餐饮结算手段发 ...

  3. java 处理emoji表情信息转换为String

    2种方式实现: 注意:如果发现运行时java.lang.NoClassDefFoundError:异常就是缺少了jar包.添加对应的jar包就可以. 一.emoji-java-4.0.0.jar实现 ...

  4. scala学习手记40 - 使用case类

    前面两节我们已经多次接触过case关键字了.case关键字不仅可以用在match/case中来执行模式匹配,也可以用来修饰类.不过用case修饰的类也主要是用来做模式匹配.在上一节曾经提到过match ...

  5. Ajax-04 jQuery Ajax 常用操作

    jQuery jQuery 其实就是一个JavaScript的类库,其将复杂的功能做了上层封装,使得开发者可以在其基础上写更少的代码实现更多的功能. jQuery Ajax a.概述 jQuery 不 ...

  6. HDU 1856 并查集

    http://acm.hdu.edu.cn/showproblem.php?pid=1856 More is better Time Limit: 5000/1000 MS (Java/Others) ...

  7. Webpack——解决疑惑,让你明白

    Webpack——解决疑惑,让你明白 极客教程 作者 关注 2016.09.29 17:46* 字数 2868 阅读 22204评论 22喜欢 80 Webpack是目前基于React和Redux开发 ...

  8. 让Android模拟器飞一会

    https://software.intel.com/zh-cn/android/articles/speeding-up-the-android-emulator-on-intel-architec ...

  9. MVC框架中的值提供机制(三)

    在MVC框架中NameValueCollectionValueProvider采用一个NameValueCollection作为数据源,DictionnaryValueProvider的数据源类型自然 ...

  10. C#学习历程(二)[基础知识]

    c#中类型的转换 1.Convert.ToInt32(string s) 这个方法的返回值是int类型,要用int类型的变量接收 如: string strNum=Console.ReadLine() ...