装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。在程序开发中经常使用到的功能,合理使用装饰器,能让我们的程序如虎添翼。

1. 函数名应用

函数名是什么?函数名是函数的名字,本质:变量,特殊的变量。

1 ) 函数名就是函数的内存地址,直接打印函数名,就是打印内存地址

def func1():

print(123)

print(func1)         #

2 ) 函数名可以作为变量

def func1():

print(111)

f = func1

f()           # f() 就是func1()

3 ) 函数名可以作为函数的参数

def func1():

print(111)

def func2(x):

x()

func2(func1)         #func1作为func2的参数

4 ) 函数名可以作为函数的返回值

def wrapper():

def inner():

print('inner')

return inner

f = wrapper()

f()

5 ) 函数名可以作为容器类类型的元素

使用for循环批量执行函数

def func1():

print('func1')

def func2():

print('func2')

def func3():

print('func3')

l1 = [func1,func2,func3]

for i in l1:

i()

像上面函数名这种,叫做第一类对象。

第一类对象( first-class object)指:

1.可在运行期创建

2.可用作函数参数或返回值

3.可存入变量的实体

*不明白?那就记住一句话,就当普通变量用

2. 闭包

1、 闭包函数 : 内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数

2、闭包的作用:爬虫、装饰器

当程序执行遇到函数执行时,会在内存空间开辟局部命名空间,当函数执行完毕,该命名空间会被销毁。但是如果这个函数内部形成闭包,则该内存空间不会随着函数执行完而消失。

3、如何判断是否是闭包:print(函数名.__closure__) 结果是 cell 说明是闭包,结果是 None 说明不是闭包。

闭包举例

def wrapper():

name = 'summer'

def inner():

print(name)

inner()

wrapper() # summer

如何判断它是否是一个闭包函数呢? 内层函数名.__closure__ cell 就是=闭包

例 1.

def wrapper():

name = 'summer'

def inner():

print(name)

inner()

print(inner.__closure__)

wrapper()

执行输出:

summer

(,)

例 2.

name = 'summer'

def wrapper():

def inner():

print(name)

inner()

print(inner.__closure__)

wrapper()

结果输出:

summer

None

返回值为None 表示它不是闭包,因为name是一个全局变量,如果函数调用了外层变量而非全局变量,那么它就是闭包。

例 3.

name = 'summer'

def wrapper2():

name1 = 'spring'

def inner():

print(name)

print(name1)

inner()

print(inner.__closure__)

wrapper2()

结果输出:

summer

spring

(,)

只要引用了外层变量至少一次,非全局的,它就是闭包

例 4:判断 下面的函数,是一个闭包吗? ******

name = 'summer'

def wraaper2(n):        #相当于n = 'summer'

def inner():

print(n)

inner()

print(inner.__closure__)

wraaper2(name)

结果输出:

summer

(,)

它也是一个闭包. 虽然wraaper2传了一个全局变量,但是在函数wraaper2内部,inner引用了外层变量,相当于在函数inner外层定义了 n = 'summer',所以inner是一个闭包函数

闭包的好处 : 当函数开始执行时,如果遇到了闭包,他有一个机制,他会永远开辟一个内存空间,将闭包中的变量等值放入其中,不会随着函数的执行完毕而消失。

举一个例子:爬3次,内存开了3次,很占用内存

from urllib.request import urlopen

content1 = urlopen('https://www.cnblogs.com/').read().decode('utf-8')

content2 = urlopen('https://www.cnblogs.com/').read().decode('utf-8')

content3 = urlopen('https://www.cnblogs.com/').read().decode('utf-8')

把它封装成闭包

from urllib.request import urlopen

def index():

url = "https://www.cnblogs.com/"

def get():

return urlopen(url).read()

return get        #return的是get,就是一个函数名

cnblog = index()

print(cnblog) # .get at 0x02F46978>

content = cnblog()

print(content) # 页面源码

这个例子,只有第一遍,是从网站抓取的。之后的执行,直接从内存中加载,节省内存空间

3.装饰器

3.1 装饰器初识

装饰器本质: 就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。

装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。

import time

def timmer(f):

def inner():

start_time = time.time()

f()

end_time = time.time()

print('此函数的执行时间为{}'.format(end_time - start_time))

return inner

def func1():

print('in func1')

time.sleep(1)

func1 = timmer(func1)

print(func1)

func1()           # 这里的func1是全新的func1,就是上面的赋值,此时相当于执行 inner函数

输出结果:

.inner at 0x03822DF8>

in func1

此函数的执行时间为1.0003533363342285

代码从上至下执行

语法糖: 想测试谁,前面加@装饰器函数,即可。 写装饰器,约定俗成,函数名为wrapper

def wrapper(func):

def inner(*args,**kwargs):

'''被装饰函数之前'''

ret = func(*args,**kwargs)

'''被装饰函数之后'''

return ret

return inner

@wrapper

def func(*args,**kwargs):

print(args,kwargs)

return 666

print(func())

输出结果:

() {}

666

装饰器利用return制造了一个假象,func()执行,其实是执行inner() , func()把原来的func()给覆盖了

3.2 装饰器传参

例 1: 上面装饰器的例子,func1,要传2个参数a,b

import time

def timmer(f):

def inner(a,b):

start_time = time.time()

f(a,b)

end_time = time.time()

print('此函数的执行时间为{}'.format(end_time - start_time))

return inner

@timmer

def func1(a,b):

print('in func1 {}{}'.format(a,b))

time.sleep(1) # 模拟程序逻辑

func1(1,2)

执行输出:

in func1 12

此函数的执行时间为1.0006024837493896

例 2: 如果有多个参数呢?改成动态参数

import time

def timmer(f):

def inner(*args,**kwargs):

start_time = time.time()

f(*args,**kwargs)

end_time = time.time()

print('此函数的执行时间为{}'.format(end_time - start_time))

return inner

@timmer

def func1(*args,**kwargs):

print('in func1 {}{}'.format(args,kwargs))

time.sleep(1) # 模拟程序逻辑

func1(1,2,a='3',b=4)

执行输出:

in func1 (1, 2){'b': 4, 'a': '3'}

此函数的执行时间为1.000101089477539

函数的执行时,*打散 ;

函数的定义时,*聚合。

from functools import wraps

def wrapper(f): # f = func1

def inner(*args,**kwargs):       #聚合,args (1,2,3)

'''执行函数之前的相关操作'''

ret = f(*args,**kwargs)      # 打散 1,2,3

'''执行函数之后的相关操作'''

return ret

return inner

@wrapper # func1 = wrapper(func1) func1 = inner

def func1(*args):       #args (1,2,3) 聚合

print(666)

return args

print(func1(*[1,2,3]))

执行输出:

666

(1, 2, 3)

例 3 *****

import time #1.加载模块

def timmer(*args,**kwargs): #2.加载变量 5.接收参数True,2,3

def wrapper(f): #6.加载变量 8.f = func1

print(args, kwargs) #9.接收timmer函数的值True,2,3

def inner(*args,**kwargs): #10.加载变量. 13.执行函数inner

if flag: #14 flag = True

start_time = time.time() #15 获取当前时间

ret = f(*args,**kwargs) #16 执行func1

time.sleep(0.3) #19 等待0.3秒

end_time = time.time() #20 获取当前时间

print('此函数的执行效率%f' % (end_time-start_time)) #21 打印差值

else:

ret = f(*args, **kwargs)

return ret #22 返回给函数调用者func1()

return inner #11 返回给函数调用者wrapper

return wrapper #7.返回给函数调用timmer(flag,2,3)

flag = True #3 加载变量

@timmer(flag,2,3) # 4.执行函数timmer(flag,2,3) 17.执行函数func1 两步:1,timmer(flag,2,3) 相当于执行wrapper 2.@wrapper 装饰器 func1 = wrapper(func1)

def func1(*args,**kwargs):

return 666 #18 返回给函数调用者f(*args,**kwargs)

print(func1()) #12 执行函数

写装饰器,一般嵌套3层就可以了

3.3 多个装饰器,装饰一个函数

def wrapper1(func): # func == f函数名

def inner1():

print('wrapper1 ,before func') # 2

func()

print('wrapper1 ,after func') # 4

return inner1

def wrapper2(func): # func == inner1

def inner2():

print('wrapper2 ,before func') # 1

func()

print('wrapper2 ,after func') # 5

return inner2

@wrapper2 # f = wrapper2(f) 里面的f==inner1 外面的f == inner2

@wrapper1 # f = wrapper1(f) 里面的f==函数名f 外面的f == inner1

def f(): # 3

print('in f')

f() # inner2()

执行输出:

wrapper2 ,before func

wrapper1 ,before func

in f

wrapper1 ,after func

wrapper2 ,after func

哪个离函数近,哪个先计算 。 最底下的先执行

执行顺序如下图:

多个装饰器,都是按照上图的顺序来的

4. 装饰器的 __name__ 和 __doc___

__name__:函数名

__doc___:函数的解释

普通函数

def func1():

"""

此函数是完成登陆的功能,参数分别是...作用。

return: 返回值是登陆成功与否(True,False)

"""

print(666)

func1()

print(func1.__name__) #获取函数名

print(func1.__doc__) #获取函数名注释说明

执行输出:

666

func1

此函数是完成登陆的功能,参数分别是...作用。

return: 返回值是登陆成功与否(True,False)

这个有什么用呢?比如日志功能,需要打印出谁在什么时间,调用了什么函数,函数是干啥的,花费了多次时间,这个时候,就需要获取函数的有用信息了

带装饰器的函数

def wrapper(f): # f = func1

def inner(*args,**kwargs): #聚合, args (1,2,3)

'''执行函数之前的相关操作'''

ret = f(*args,**kwargs) # 打散 1,2,3

'''执行函数之后的相关操作'''

return ret

return inner

@wrapper

def func1():

"""

此函数是完成登陆的功能,参数分别是...作用。

return: 返回值是登陆成功与否(True,False)

"""

print(666)

return True

func1()

print(func1.__name__)

print(func1.__doc__)

执行输出:

666

inner

执行函数之前的相关操作

函数装饰之后,相当于执行了inner函数,所以输出inner

为了解决这个问题,需要 调用一个模块wraps

wraps将 被修饰的函数(wrapped) 的一些属性值赋值给修饰器函数(wrapper) ,最终让属性的显示更符合我们的直觉

from functools import wraps

def wrapper(f): # f = func1

@wraps(f) #f是被装饰的函数

def inner(*args,**kwargs): #聚合args (1,2,3)

'''执行函数之前的相关操作'''

ret = f(*args,**kwargs) # 打散 1,2,3

'''执行函数之后的相关操作'''

return ret

return inner

@wrapper

def func1():

"""

此函数是完成登陆的功能,参数分别是...作用。

return: 返回值是登陆成功与否(True,False)

"""

print(666)

return True

func1()

print(func1.__name__)

print(func1.__doc__)

执行输出:

666

func1

此函数是完成登陆的功能,参数分别是...作用。

return: 返回值是登陆成功与否(True,False)

python中的类装饰器应用场景_这是我见过最全面的Python装饰器教程了!相关推荐

  1. python装饰器作用和功能_这是我见过最全面的Python装饰器详解!没有学不会这种说法!...

    今天的任务比较繁重,因为我们要一起来学习Python中比较重要比较牛逼比较难的装饰器. 我将会和大家一起通过代码的形式来迷你银行存款取款的功能,然后通过引入装饰器来一步一步优化代码. 废话不多说梦开始 ...

  2. 这是我见过最全面的Python装饰器详解!没有学不会这种说法

    python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,才有点点开始明白了. 学习python中有什么不懂的地方,小编这 ...

  3. 这是我见过最全面的Python装饰器详解 没有学不会这种说法

    python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,才有点点开始明白了. 待会我将会和大家一起通过代码的形式来迷你银 ...

  4. python装饰器详解-这是我见过最全面的Python装饰器详解!没有学不会这种说法!...

    今天的任务比较繁重,因为我们要一起来学习Python中比较重要比较牛逼比较难的装饰器. 我将会和大家一起通过代码的形式来迷你银行存款取款的功能,然后通过引入装饰器来一步一步优化代码. 废话不多说梦开始 ...

  5. python十大重点_你见过的最全面的 Python 重点

    由于总结了太多的东西,所以篇幅有点长,这也是我'缝缝补补'总结了好久的东西. Py2 VS Py3print成为了函数,python2是关键字 不再有unicode对象,默认str就是unicode ...

  6. python双除号_你见过的最全面的 Python 重点

    来源:二十一    链接: https://segmentfault.com/a/1190000018737045 由于总结了太多的东西,所以篇幅有点长,这也是我'缝缝补补'总结了好久的东西. Py2 ...

  7. python壁纸超清全面屏_你见过的最全面的python重点

    首先和大家说个对不起,由于总结了太多的东西,所以篇幅有点长,这也是我"缝缝补补"总结了好久的东西,对于Nginx的东西我没总结在这里,大家可以Python聚焦看,点击直达专栏哦. ...

  8. 超实用,这是我见过最全面的python入门教程,高中生不要错过

    Python 是一门开源免费.通用型的脚本编程语言,它上手简单,功能强大,坚持「极简主义」. Python 类库(模块)极其丰富,这使得 Python 几乎无所不能,不管是传统的 Web 开发.PC ...

  9. Python中的类、实例以及方法,MRO继承解析顺序以及Mixin类

    Contents 1. 什么是类和实例 2. 类的实例方法.类方法和静态方法 3. MRO是什么,描述其查找顺序 4. Mixin是什么,描述其应用场景 5. References 1. 什么是类和实 ...

最新文章

  1. 代码模拟实现十六进制转二进制
  2. linux sqlplus 密码有$
  3. jasmine spyOn的单步调试
  4. Docker 数据持久化的三种方案
  5. WeX5 Model 里data ,baasData 数据过滤条件清除 数据初始化
  6. 如何让service不被系统杀掉
  7. Shadow Map在DirectX9.0 SDK Sample 的实现方法
  8. 你还在用 BeanUtils?试试 MapStruct,优雅的对象转换解决方案!
  9. C#下对象与JSON串互相转换
  10. win7怎么设置悬浮桌面便签
  11. 360加固签名验证_360加固助手签名工具怎么用
  12. 抖音seo,抖音优化系统,抖音seo矩阵系统源码技术搭建
  13. RabbitMQ笔记
  14. 数字化医院中智慧医疗的具体应用
  15. c语言把bit数据合为一个字节,C语言中怎么定义bit型数据
  16. 信息检索——名词解释、简答题
  17. Solidity 介绍
  18. shader实现星空效果
  19. 【日常问题】API文档的.chm后缀自动生成.chw后缀文件
  20. SEO建站优化要注意的一些方面

热门文章

  1. 大数据新手之路二:安装Flume
  2. keepalive的作用
  3. 阿里巴巴2014研发project师实习生面试经历
  4. 金山毒霸的云查杀很牛X
  5. ospf 单区域配置
  6. java list用法_Java List 用法详解及实例分析
  7. 786. 第 K 个最小的素数分数
  8. 使用Hadoop所需要的一些Linux基础
  9. leetcode881. 救生艇(贪心算法加双指针)
  10. aws 弹性三剑客_AWS和弹性:超越用户需求