装饰器。。。。。。

定义:本质是函数,为其他函数添加附加功能

原则: 1.不能修改被装饰的函数的源代码

2.不能修改被装饰函数的调用方式

仔细观察下面代码,看看有什么发现。

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

import time

# 内嵌函数
def timmer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
return res return wrapper # 返回函数名 @timmer
def foo():
time.sleep(3)
print('from foo') foo()

高阶函数。。。。。下面的例子中foo就是属于一个高阶函数。

'''
高阶函数:
1、函数接收的参数是一个函数名
2、函数的返回值是一个函数名
只要满足其中一个就属于高阶函数
''' def fun():
print("from fun") def foo(fun1):
fun1() foo(fun)

返回值是函数名的高阶函数

def fun():
print("from fun") def foo(fun1):
return fun1 foo(fun)()

函数嵌套。。。。。。通过下面的例子,可以看出,函数内可以套函数,而函数也是一个变量,

通过locals()可以看到。

'''
函数嵌套
''' def fun1():
print("from fun1") def fun2():
print("from fun2") print(locals()) fun1()
# 运行结果
#from fun1
#{'fun2': <function fun1.<locals>.fun2 at 0x000002A2C4D4AD90>}

闭包闭包,一个函数一个包。。。主要还是作用域,请看https://blog.csdn.net/June_King/article/details/87090970

重点来了。装饰器。。。。。。

# 简单的装饰器例子
def timer(func):
def wrapper():
func() return wrapper def test():
time.sleep(3)
print("test函数执行完毕") res = timer(test)
res()

这是不对的,前面说过,装饰器不能修改被装饰函数的源代码,不能修改被装饰函数的调用方式。

这里调用时,修改了调用的方式。。。

那这样呢?

test = timer(test)
test()

看着是没有修改调用方式,但是每次调用时都会重新赋值。。。这样不合理

那应该怎么做?下面这样写,仅仅是在函数调用之前加上@装饰器名字即可

@timer
test()

看下面的例子,看看都打印了什么。

def timer(func):
def wrapper():
func() return wrapper @timer
def test():
time.sleep(2)
print("test函数执行完毕")
return "test()的返回结果" res = test()
print(res)

可以发现,我们并没有得到test()函数的返回值,如果想要得到被装饰函数的返回值,需要这样写

def timer(func):
def wrapper():
res = func()
return res
return wrapper

在装饰器中通过变量来接收被装饰函数的返回值,然后利用return返回。这样一个带有返回值的装饰器就书写完成了。

这些还远远不够,有时候我们被修饰的函数还需要传入一些参数

def timer(func):
def wrapper(name, age):
res = func(name, age)
return res return wrapper @timer
def test(name, age):
time.sleep(2)
print("name:%s,age:%d," % (name, age))
print("test函数执行完毕")
return "test()的返回结果" res = test('june', 18)
print(res)

上面的例子虽然可以传递参数,但依然存在不足,当test()的参数变化时,上面的例子就不能用了,需要对装饰器进行改进

def timer(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res return wrapper

上面的这个例子可以实现无论被修饰函数的参数如何让改变,都能够接收。关于*args,**kwargs可以参考https://blog.csdn.net/June_King/article/details/87085052

好了,目前为止我们写的装饰器可以传入参数,也可以拥有返回值了,那么如果我们的装饰器还需要参数的话,那。。。。

def auth(filed):
print(filed) def fun1(fun): def fun2(*args, **kwargs):
fun(*args, **kwargs) return fun2 return fun1 @auth("我是装饰器的参数")
def foo():
print("from foo") foo()

在原来的基础上再加一层函数。。。

小结,不修改原函数代码,不修改原函数的调用方式。

python迭代器、生成器、装饰器之装饰器的更多相关文章

  1. Python迭代器生成器与生成式

    Python迭代器生成器与生成式 什么是迭代 迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果.每一次对过程的重复称为一次"迭代",而每一次迭代得到的结果会作为下一次迭 ...

  2. Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发

    本节大纲 迭代器&生成器 装饰器  基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...

  3. Python 迭代器&生成器

    1.内置参数     Built-in Functions     abs() dict() help() min() setattr() all() dir() hex() next() slice ...

  4. python 迭代器 生成器

    迭代器 生成器 一 什么是迭代器协议 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前 ...

  5. python迭代器,生成器,推导式

    可迭代对象 字面意思分析:可以重复的迭代的实实在在的东西. list,dict(keys(),values(),items()),tuple,str,set,range, 文件句柄(待定) 专业角度: ...

  6. 4.python迭代器生成器装饰器

    容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元素存储在内存中 ...

  7. Python迭代器&生成器&装饰器

    1. 迭代器 1.1 可迭代对象(Iterator) 迭代器协议:某对象必须提供一个__next__()方法,执行方法要么返回迭代中的下一项,要么引起一个Stopiteration异常,以终止迭代(只 ...

  8. Python迭代器,生成器,装饰器

    迭代器 通常来讲从一个对象中依次取出数据,这个过程叫做遍历,这个手段称为迭代(重复执行某一段代码块,并将每一次迭代得到的结果作为下一次迭代的初始值). 可迭代对象(iterable):是指该对象可以被 ...

  9. Python(迭代器 生成器 装饰器 递归 斐波那契数列)

    1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大优 ...

随机推荐

  1. 关于nginx的动静分离配置和分析

    最近博客的图片多了起来(其实也不多,主要因为服务器差劲),于是打算将静态文件剥离出来,做一个分离. 如何安装和配置nginx就不说了,再server节点下面添加如下: 意思是对所有以这些为后缀的文件都 ...

  2. CSP-S 2019 第二轮 退役记

    Day 0 复习数论,复习网络流,复习动态DP,复习ac自动机,复习后缀自动机- Day 1 进考场,得到解压密码,跟时事热点没有什么关系. 感觉键盘有点难受,右半部分包括退格.方向键.回车都比较黏. ...

  3. 洛谷 P2580 于是他错误的点名开始了 题解

    每日一题 day10 打卡 Analysis trie树模板题,只需用到简单的插入和查询就好了 如果想要学trie树,见信息学奥赛一本通·提高篇P82 #include<iostream> ...

  4. linux系列(十五):tail命令

    1.命令格式: tail[必要参数][选择参数][文件] 2.命令功能: 用于显示指定文件末尾内容,不指定文件时,作为输入信息进行处理.常用查看日志文件. 3.命令参数: -f 循环读取 -q 不显示 ...

  5. fgetc,getc,fputc,putc,putchar,getchar

    转自 http://blog.csdn.net/todd911/article/details/8952565 输入输出函数家族 家族名                   目的           ...

  6. 3、spark Wordcount

    一.用Java开发wordcount程序 1.开发环境JDK1.6 1.1 配置maven环境 1.2 如何进行本地测试 1.3 如何使用spark-submit提交到spark集群进行执行(spar ...

  7. vue+elementui 开发的网站IE浏览器加载白屏(不兼容)解决办法

    1.需要检查一下 export default { name: 'aa',-------vue的name是不可以重复的-----这个是决定性原因 data() { return {} } 2.变量声明 ...

  8. jmeter压测过程中报java.lang.NoClassDefFoundError: org/bouncycastle/jce/provider/BouncyCastleProvider

    由于在java中添加了第三方安全策略文件,具体请看https://www.cnblogs.com/mrjade/p/10886378.html,导致在用jmeter压测过程中会遇到以下错误 解决办法: ...

  9. P5346 【XR-1】柯南家族(后缀数组+主席树)

    题目 P5346 [XR-1]柯南家族 做法 聪明性是具有传递性的,且排列是固定的 那么先预处理出每个点的名次,用主席树维护\(k\)大值 一眼平衡树,遍历的同时插入\(O(log^2n)\),总时间 ...

  10. 小程序tabBar的使用

    这个selectedIconPath一定要写,否则选中的那个图片是不会显示的 下面是不写的现象: onTabItemTap的使用---下面的现象说明:只有tab值向哪个页面才会触发.