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

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

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. redis安装优化:

    1)内存分配控制: vm.overcommit_memoryredis启动时肯呢个会出现这样的日志: :M Apr ::! Background save may fail under low mem ...

  2. Android Gradle 构建工具(Android Gradle Build Tools)是什么?

    转载地址:http://mrfu.me/android/2015/07/17/New_Android_Gradle_Build_Tools/ 译者地址:[翻]一览新的 Android Gradle 构 ...

  3. zabbix监控使用

    zabbix监控 通过导入/导出zabbix配置文件,我们可以将自己写好的模板等配置在网络上分享,我们也可以导入网络上分享的配置文件,配置文件有两种格式,分为xml与json,通过zabbix管理界面 ...

  4. JS 闭包应用

    1. 代替全局变量 //闭包应用1:代替全局变量的使用 //多个函数都用到一个变量,通常我们会定义一个全局变量,然后在各函数中应用它,//为了避免使用全局变量,可以通过使用立即执行函数定义临时变量,子 ...

  5. linux 安装unrar

    Centos 6 32位下安装 wget http://pkgs.repoforge.org/unrar/unrar-4.2.3-1.el6.rf.i686.rpmrpm -ivh unrar-4.2 ...

  6. sklearn学习笔记之开始

    简介   自2007年发布以来,scikit-learn已经成为Python重要的机器学习库了.scikit-learn简称sklearn,支持包括分类.回归.降维和聚类四大机器学习算法.还包含了特征 ...

  7. JNIjw03

    1.VC6(CPP)的DLL代码: #include<stdio.h> #include "jniZ_JNIjw03.h" JNIEXPORT void JNICALL ...

  8. crm开发(基于ssh)(1)

    搭建crm练习ssh环境 第一步 导入jar包 第二步 搭建struts2环境 (1)创建action,创建struts.xml配置文件,配置action (2)配置struts2的过滤器 第三步 搭 ...

  9. python学习笔记(异常处理)

    上次提到正则表达式 当未匹配到数据返回值 None 再使用 match.group 会出现异常 AttributeError 为了避免异常我改成“ match != None” 这次加入异常处理 #! ...

  10. yii2: 上传图片,生成目录

    1.单个文件上传 首先建立一个模型models/UploadForm.php,内容如下 namespace app\models; use yii\base\Model; use yii\web\Up ...