python笔记3:装饰器

Table of Contents

01介绍

02实现装饰器

03装饰器的作用 对有参函数的装饰

04 装饰多个函数

05不定长参数的函数装饰

06 返回值函数装饰 通用装饰器

07多个装饰器对同一个函数装饰

08应用

09类装饰器


01介绍

不会装饰器,不能说会python哟

扫描二维码关注公众号,回复: 13139301 查看本文章

def foo():

       print('foo')

 

foo#函数名指向函数

foo()#执行函数

 

foo=lambda x: x+1#foo变量名被指向匿名函数

foo()#执行lambda表达式

Py把函数名、方法名、变量名都当作变量名对待,所以不能相同

只要有相同的,则用的时候就是最后定义的一个

需求:基础平台部门写功能,业务部门调用(容易被裁员)

让业务部门调用的时候加权限验证,不加不能调用功能函数

#法1:冗余过多

def f1():

       #权限验证

       print('f1')

def f2():

       #权限验证

       print('f2')

 

f1()

f2()

#法2

def check_login():

       #权限验证

       pass

 

def f1():

       check_login()

       print('f1')

def f2():

       check_login()

       print('f2')

 

f1()

f2()

开放封闭原则规定已经实现的功能代码不能修改(封闭),但可以扩展(开放)

装饰器效果

def set_func(func):

       def call_func():

              print("权限验证")

              func()

       return call_func

 

@set_func#在函数执行前加代码

def test1():

       #set_func()#类似效果

       print("test1")

 

test1()

02实现装饰器

装饰器实现过程:

def set_func(func):#传入的指针是test1

       def call_func():

              print("权限验证")

              func()

       return call_func

 

def test1():

       print("test1")

 

ret=set_func(test1)#ret得到call_func指针

ret()#执行print("权限验证")和调用func()即指向test1

test1=set_func(test1)#不用修改调用的函数名,重新修改指针

test1()#执行print("权限验证")和func()即test1

@set_func可看作一种简略写法

@set_func#等价于test1=set_func(test1)

def test1():

       print("test1")

由于装饰器(修饰器)的闭包实现过程是整个调用原函数,新加的功能只能在原函数调用之前或之后执行,不能在执行到一半时插入

03装饰器的作用 对有参函数的装饰

装饰器能够实现对功能的扩展,同时不改变调用的函数名

作用:如计算函数运行的时间

Import time

time.time()

1508763827.814883

整数部分是1970年到现在秒数(Unix时间戳)

import time

def set_func(func):#传入的指针是test1

       def call_func():

              start_time=time.time()

              func()

              stop_time=time.time()

              print("all time is %f" % (stop_time - start_time))

       return call_func

 

@set_func#等价于test1=set_func(test1)

def test1():

       print("test1")

test1()#执行print("权限验证")和func()即test1

对无参数、返回值函数最简单

对有参数无返回值函数装饰

def set_func(func):#传入的指针是test1

       def call_func(a):#2.接收到100

              print("权限验证")

              func(a)#3.100作为实参调用test1

       return call_func

 

@set_func

def test1(num):

       print("test1:%d" % num)

 

test1(100)#1.100给了call_fun

04 装饰多个函数

 同一个装饰器装饰多个函数

def set_func(func):

       def call_func(a):

              print("权限验证")

              func(a)

       return call_func

 

@set_func

def test1(num):

       print("test1:%d" % num)

 

@set_func

def test2(num):

       print("test2:%d" % num)

 

test1(100)#1.100给了call_fun

test2(200)

两次装饰分别创建多个闭包

test1、test2分别指向另一个函数,该函数分别嵌套原本的func(test1、test2)

装饰器@写完就已经装饰了,而不需要等调用test1()

def set_func(func):

       print("开始装饰")

       def call_func(a):

              print("权限验证")

              func(a)

       return call_func

 

@set_func

def test1(num):

       print("test1:%d" % num)

 

#test1(100)

test1未运行

终端打印出:开始装饰

05不定长参数的函数装饰

不定长参数的即便使用:

def test1(num,*args,**kwargs):

       print("test1:%d" % num)

       print("test1:", args)#作为元组打印

       print("test1:", kwargs)#作为元组打印

 

test1(1,2,3,mm=1)

其中mm=1为关键字参数

输出结果:

test1:1

test1:(2,3)

test1:{‘mm’:1}

使用解释器:

def set_func(func):

       print("开始装饰")

       def call_func(*args,**kwargs):#num1在args中以元组保存

              print("权限验证")

              func(*args,**kwargs)#传递处也要带*,*代表对元组拆包,**代表对字典拆

       return call_func

 

@set_func

def test1(num,*args,**kwargs):#*代表多余的普通参数给args,**代表关键字参数给kwargs

       print("test1:%d" % num)

       print("test1:", args)

       print("test1:", kwargs)

 

test1(1,2,3,mm=1)#调用call_func

传递可变参数时不能写成func(args,kwargs)否则只传递了一个元组一个字典

06 返回值函数装饰 通用装饰器

def set_func(func):

       print("开始装饰")

       def call_func(*args,**kwargs):#num1在args中以元组保存

              print("权限验证")

              return func(*args,**kwargs)#将接收到的返回值传递

       return call_func

 

@set_func

def test1(num,*args,**kwargs):#*代表多余的普通参数给args,**代表关键字参数给kwargs

       print("test1:%d" % num)

       print("test1:", args)

       print("test1:", kwargs)

       return "ok"#谁调用的test1就向谁返回

 

ret=test1(1)#调用call_func

print(ret)

无返回值函数可适用:

一般接收无返回值函数,拿到的都是none

使用该装饰器装饰无返回值的函数,return none结果也一样是none

多返回值可适用:

多返回值时返回元组

def set_func(func):

       print("开始装饰")

       def call_func(*args,**kwargs):

              print("权限验证")

              return func(*args,**kwargs)

       return call_func

 

@set_func

def test1(num,*args,**kwargs):

       print("test1:%d" % num)

       print("test1:", args)

       print("test1:", kwargs)

       return "ok","2"#多返回值时返回元组

 

ret=test1(1)#调用call_func

print(ret)

 

通用装饰器主要有3点:

  1. call_func(*args,**kwargs)接收可变参数
  2. func(*args,**kwargs)传递实参时拆包
  3. return func将接收到的返回值传递

07多个装饰器对同一个函数装饰

def add_verify1(func):

       print("开始1装饰")

       def call_func(*args,**kwargs):#num1在args中以元组保存

              print("装饰1")

              return func(*args,**kwargs)#将接收到的返回值传递

       return call_func

def add_verify2(func):

       print("开始2装饰")

       def call_func(*args,**kwargs):#num1在args中以元组保存

              print("装饰2")

              return func(*args,**kwargs)#将接收到的返回值传递

       return call_func

 

@add_verify1

@add_verify2

def test1():

       print("test1")

 

test1()

输出结果

开始2装饰

开始1装饰

装饰1

装饰2

装饰与执行顺序不同

装饰add_verify1时,将add_verify2包括以下当成整个函数,需要先装饰下面的,下面的就变成新闭包

@add_verify1#等价于test1=add_verify1(test1),此时的test1指向已经改变

@add_verify2#等价于test1=add_verify2(test1)

def test1():

       print("test1")

08应用

对原函数返回值加"<h1></h1>"标签

def set_func_1(func):

       def call_func(*args,**kwargs):

              return "<h1>"+func(*args,**kwargs)+"</h1>"

       return call_func

 

@set_func_1

def get_str():

       return "haha"

 

print(get_str())

再加"<td></td>"标签

def set_func_1(func):

       def call_func(*args,**kwargs):

              # print("装饰1")

              return "<h1>"+func(*args,**kwargs)+"</h1>"

       return call_func

def set_func_2(func):

       def call_func(*args,**kwargs):

              # print("装饰1")

              return "<td>"+func(*args,**kwargs)+"</td>"

       return call_func

 

@set_func_1

@set_func_2

def get_str():

       return "haha"

 

print(get_str())

输出结果:

<h1><td>haha</td></h1>

因为h1装饰的在最上面,执行的时候再递归调用td的装饰

09类装饰器

用类对函数装饰

class Test(object):

       def __init__(self,func):#带self的可算作实例方法,但肯定不是类方法

              self.func=func#存下func引用

       def __call__(self):

              print("装饰器功能")

              return self.func()#指向get_str

 

@Test#get_str=Test(get_str)创建Test类的实例对象

def get_str():

       return "haha"

 

print(get_str())#调用时调用的是类装饰器的call方法

若要改成通用装饰器:get_str()调用类的call方法,所以参数也在call接收

类方法,静态方法可以通过类名调用,如@Test.jingtaifangfa

猜你喜欢

转载自blog.csdn.net/lagoon_lala/article/details/106035609