十九、python沉淀之路--装饰器
一、实现装饰器的预备知识
装饰器 = 高阶函数 + 函数嵌套 + 闭包
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沉淀之路--装饰器的更多相关文章
- Python修炼之路-装饰器、生成器、迭代器
装饰器 本质:是函数,用来装饰其他函数,也就是为其他函数添加附加功能. 使用情景 1.不能修改被装饰的函数的源代码: 2.不能修改被装饰的函数的调用方式. 在这两种条件下,为函数添加附加 ...
- Python学习之路——装饰器
开放封闭原则:不改变调用方式与源代码上增加功能 ''' 1.不能修改被装饰对象(函数)的源代码(封闭) 2.不能更改被修饰对象(函数)的调用方式,且能达到增加功能的效果(开放) ''' 装饰器 # 把 ...
- 十、python沉淀之路--高阶函数初识
一.高阶函数:分两种:一种是返回值中包含函数体:另一种是把一个函数体当作了参数传给了另一个函数 1.返回值中包含函数体 例1. def test(): print('这是一个测试') return t ...
- Python中利用函数装饰器实现备忘功能
Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下 " ...
- python函数与方法装饰器
之前用python简单写了一下斐波那契数列的递归实现(如下),发现运行速度很慢. def fib_direct(n): assert n > 0, 'invalid n' if n < 3 ...
- guxh的python笔记三:装饰器
1,函数作用域 这种情况可以顺利执行: total = 0 def run(): print(total) 这种情况会报错: total = 0 def run(): print(total) tot ...
- 十九. Python基础(19)--异常
十九. Python基础(19)--异常 1 ● 捕获异常 if VS异常处理: if是预防异常出现, 异常处理是处理异常出现 异常处理一般格式: try: <............. ...
- python设计模式之内置装饰器使用(四)
前言 python内部有许多内建装饰器,它们都有特别的功能,下面对其归纳一下. 系列文章 python设计模式之单例模式(一) python设计模式之常用创建模式总结(二) python设计模式之装饰 ...
- python 3.x 的装饰器笔记
今天学到了python的装饰器,感觉这个东西还是稍微有些复杂,所以记录下来,方便以后的查找.虽然标题是python 3.x的装饰器,但是我也没有怎么用过python 2.x,感觉上应该是和python ...
随机推荐
- java没有指针
先说结论:java没有指针,它使用对象引用来替代指针 备注:c/c++的引用和java的引用完全不是一个东西 c/c++的引用是同一块内存的不同名字 java的引用指向一个对象,引用本身也占用了内存 ...
- github Git-fork-别人的项目后更新代码的方法
用github还处于菜的阶段,遇到问题简单记录. 举个例子,需要 fork 这个项目 https://github.com/tarobjtu/WebFundamentals.git 点击 for ...
- 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 ...
- bat脚本——删除当前文件夹的所有指定文件类型
学了这个,就不用手动删除大量的指定的文件类型,可以做到双击bat处理文件就可以删除了 比如说,我要删除当前文件夹下的txt文件和doc文件,代码如下 del *.txt* del *.doc* 其原理 ...
- 4.微信小程序-B站:先把首页造出来
(小安娜:失踪人口已上线,大家快来喷喷喷他!),sorry++,最近身边发生太多事情,导致这最关键的实战开篇都未写,(小安娜-分身1:懒就是懒,不负责任,我之前学的都忘了),(小安娜-分身2:上一篇双 ...
- C语言查找算法之顺序查找、二分查找(折半查找)
C语言查找算法之顺序查找.二分查找(折半查找),最近考试要用到,网上也有很多例子,我觉得还是自己写的看得懂一些. 顺序查找 /*顺序查找 顺序查找是在一个已知无(或有序)序队列中找出与给定关键字相同的 ...
- tyvj 1055 沙子合并 区间dp经典模型,石子合并
P1055 沙子合并 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 设有N堆沙子排成一排,其编号为1,2,3,…,N(N<=300).每堆沙子 ...
- 画龙点睛 之RabbitMQ 初来乍到
消息队列解决了什么问题 1. 异步处理 2. 应用解耦 3. 流量削峰 4. 日志处理...... 安装RabbitMQ (这里的安装我只仅仅说一下linux 的安装 如果想安装windows 版 可 ...
- yii2:doajax(post)会报500错误
yii2:doajax(post)会报500错误:这是因为yii2开启了防御csrf的攻击机制,可去先去掉,在控制器里去掉:public $enableCsrfValidation = false , ...
- uva11827gcd
gcd裸题,不过输入要注意gets会tle,要用快速读入 #include<map> #include<set> #include<cmath> #include& ...