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

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

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. java没有指针

    先说结论:java没有指针,它使用对象引用来替代指针 备注:c/c++的引用和java的引用完全不是一个东西 c/c++的引用是同一块内存的不同名字 java的引用指向一个对象,引用本身也占用了内存 ...

  2. github Git-fork-别人的项目后更新代码的方法

     用github还处于菜的阶段,遇到问题简单记录.   举个例子,需要 fork 这个项目 https://github.com/tarobjtu/WebFundamentals.git 点击 for ...

  3. TNS-12541: TNS:no listener , TNS-12542: TNS:address already in use

    查看数据库监听状态不对$ lsnrctl status LSNRCTL for IBM/AIX RISC System/6000: Version 10.2.0.5.0 - Production on ...

  4. bat脚本——删除当前文件夹的所有指定文件类型

    学了这个,就不用手动删除大量的指定的文件类型,可以做到双击bat处理文件就可以删除了 比如说,我要删除当前文件夹下的txt文件和doc文件,代码如下 del *.txt* del *.doc* 其原理 ...

  5. 4.微信小程序-B站:先把首页造出来

    (小安娜:失踪人口已上线,大家快来喷喷喷他!),sorry++,最近身边发生太多事情,导致这最关键的实战开篇都未写,(小安娜-分身1:懒就是懒,不负责任,我之前学的都忘了),(小安娜-分身2:上一篇双 ...

  6. C语言查找算法之顺序查找、二分查找(折半查找)

    C语言查找算法之顺序查找.二分查找(折半查找),最近考试要用到,网上也有很多例子,我觉得还是自己写的看得懂一些. 顺序查找 /*顺序查找 顺序查找是在一个已知无(或有序)序队列中找出与给定关键字相同的 ...

  7. tyvj 1055 沙子合并 区间dp经典模型,石子合并

    P1055 沙子合并 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述     设有N堆沙子排成一排,其编号为1,2,3,…,N(N<=300).每堆沙子 ...

  8. 画龙点睛 之RabbitMQ 初来乍到

    消息队列解决了什么问题 1. 异步处理 2. 应用解耦 3. 流量削峰 4. 日志处理...... 安装RabbitMQ (这里的安装我只仅仅说一下linux 的安装 如果想安装windows 版 可 ...

  9. yii2:doajax(post)会报500错误

    yii2:doajax(post)会报500错误:这是因为yii2开启了防御csrf的攻击机制,可去先去掉,在控制器里去掉:public $enableCsrfValidation = false , ...

  10. uva11827gcd

    gcd裸题,不过输入要注意gets会tle,要用快速读入 #include<map> #include<set> #include<cmath> #include& ...