python装饰器函数执行后日志_python函数 | 装饰器详解

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

一、函数名应用

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

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

deffunc1():print(123)print(func1)         #

(2)函数名可以作为变量

deffunc1():print(111)

f=func1

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

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

deffunc1():print(111)deffunc2(x):

x()

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

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

defwrapper():definner():print('inner')returninner

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.可存入变量的实体

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

二、闭包

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

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

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

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

闭包举例

defwrapper():

name= 'summer'

definner():print(name)

inner()

wrapper()#summer

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

例1.

defwrapper():

name= 'summer'

definner():print(name)

inner()print(inner.__closure__)

wrapper()

执行输出:

summer

(,)

例2.

name = 'summer'

defwrapper():definner():print(name)

inner()print(inner.__closure__)

wrapper()

结果输出:

summer

None

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

例3.

name = 'summer'

defwrapper2():

name1= 'spring'

definner():print(name)print(name1)

inner()print(inner.__closure__)

wrapper2()

结果输出:

summer

spring

(,)

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

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

name = 'summer'

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

definner():print(n)

inner()print(inner.__closure__)

wraaper2(name)

结果输出:

summer

(,)

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

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

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

from urllib.request importurlopen

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 importurlopendefindex():

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

defget():returnurlopen(url).read()return get        #return的是get,就是一个函数名

cnblog=index()print(cnblog) #.get at 0x02F46978>

content =cnblog()print(content) #页面源码

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

三、装饰器

1 装饰器初识

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

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

importtimedeftimmer(f):definner():

start_time=time.time()

f()

end_time=time.time()print('此函数的执行时间为{}'.format(end_time -start_time))returninnerdeffunc1():print('in func1')

time.sleep(1)

func1=timmer(func1)print(func1)

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

输出结果:

.inner at 0x03822DF8>

in func1

此函数的执行时间为1.0003533363342285

代码从上至下执行

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

defwrapper(func):def inner(*args,**kwargs):'''被装饰函数之前'''ret= func(*args,**kwargs)'''被装饰函数之后'''

returnretreturninner

@wrapperdef func(*args,**kwargs):print(args,kwargs)return 666

print(func())

输出结果:

() {}

666

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

2. 装饰器传参

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

importtimedeftimmer(f):definner(a,b):

start_time=time.time()

f(a,b)

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

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

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

func1(1,2)

执行输出:

in func1 12

此函数的执行时间为1.0006024837493896

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

importtimedeftimmer(f):def inner(*args,**kwargs):

start_time=time.time()

f(*args,**kwargs)

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

@timmerdef 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 importwrapsdef wrapper(f): #f = func1

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

'''执行函数之前的相关操作'''ret= f(*args,**kwargs)      #打散 1,2,3

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

returnretreturninner

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

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

print(666)returnargsprint(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.多个装饰器,装饰一个函数

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

definner1():print('wrapper1 ,before func') #2

func()print('wrapper1 ,after func') #4

returninner1def wrapper2(func): #func == inner1

definner2():print('wrapper2 ,before func') #1

func()print('wrapper2 ,after func') #5

returninner2

@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

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

执行顺序如下图:

1518468-20190910210843673-1576155199.png

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

4. 装饰器的__name__和__doc___

__name__:函数名

__doc___:函数的解释

普通函数

deffunc1():"""此函数是完成登陆的功能,参数分别是...作用。

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

print(666)

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

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

执行输出:666func1

此函数是完成登陆的功能,参数分别是...作用。return: 返回值是登陆成功与否(True,False)

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

带装饰器的函数

def wrapper(f): #f = func1

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

'''执行函数之前的相关操作'''ret= f(*args,**kwargs) #打散 1,2,3

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

returnretreturninner

@wrapperdeffunc1():"""此函数是完成登陆的功能,参数分别是...作用。

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

print(666)returnTrue

func1()print(func1.__name__)print(func1.__doc__)

执行输出:

666

inner

执行函数之前的相关操作

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

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

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

from functools importwrapsdef wrapper(f): #f = func1

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

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

'''执行函数之前的相关操作'''ret= f(*args,**kwargs) #打散 1,2,3

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

returnretreturninner

@wrapperdeffunc1():"""此函数是完成登陆的功能,参数分别是...作用。

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

print(666)returnTrue

func1()print(func1.__name__)print(func1.__doc__)

执行输出:

666

func1

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

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

千心万苦写了的博客,如果您觉得本篇文章有帮助到您,请麻烦右下角点赞呦!算是给我的鼓励!我会继续加油, 争取给大家分享到有用的知识!相互学习,一起进步!谢谢啦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值