zoukankan      html  css  js  c++  java
  • Day4-装饰器

    装饰器,本质是函数,为其它函数添加附加功能。

    装饰器对被装饰的函数没有任何影响,原则:

    1.不能修改被装饰的函数的源代码;2.不能修改调用方式;

    高阶函数+嵌套函数,实现装饰器,准备知识如下:

    1.函数和变量的区别:

    变量存在内存中,比如x=1 ,1存在内存中,x就是内存的门牌号。若y=x,y也是一次引用,即y也是门牌号,清除变量1的话必须清除x和y。
    def test(): #定义了test函数,即函数体存在内存中,test为门牌号
          pass
    test = '函数体 '

    python的内存回收器由python解释器回收的,清除变量通过清除所有门牌号的方式清除。

    lambda匿名函数:没有起名,正是因为没有名字,它就没有门牌号,立马被python解释器回收掉
    calc=lambdax:x*3
    print(calc(3))
    9

    总结:函数就是变量,定义一个函数,等于把函数体给了函数名。变量有内存回收机制,函数一样。
    先声明再调用,只要在调用之前声明就可以正常执行。因为声明是定义函数名,把函数体存在内存中。

    2.高阶函数,满足的条件:

    a.把一个函数名当做实参传给另外一个函数;(不修改被装饰函数源代码的情况下为其添加功能)
    b.返回值中包含函数名(不修改函数的调用方式)

     1 import time
     2 def bar():
     3     time.sleep(3)
     4     print("in the bar")
     5 
     6 def test1(func):
     7     start_time = time.time()
     8     func()
     9     stop_time=time.time()
    10     print("in the func run time is %s" %(start_time-stop_time))
    11 
    12 test1(bar)
    13 结果:
    14 in the bar
    15 in the func run time is -3.014805555343628
    View Code

    3.嵌套函数:在def函数体内再def声明一个函数,叫嵌套函数

     1 #函数的调用
     2 def test1():
     3     test2()  #函数的调用,不叫嵌套
     4 test1()
     5 
     6 #嵌套函数
     7 def foo():
     8     print("in the foo")
     9     def bar():
    10         print("in the bar")
    11     bar() #局部变量必须在函数内部调用
    12 foo()
    13 #bar()  #这引用是不对的
    View Code

    4.装饰器的形成步骤

    a.改变函数调用方式:正常为test1(),变为deco(test1)

    需求:计算test1和test2函数运行时间

     1 import time
     2 def deco(func):
     3     start_time = time.time()
     4     func()
     5     stop_time = time.time()
     6     print("the func run time is %s" %(start_time-stop_time))
     7 def test1():
     8     time.sleep(3)
     9     print("in the test1")
    10 def test2():
    11     time.sleep(3)
    12     print("in the test2")
    13 deco(test1) #test1代表函数/变量,而test1()表示返回test1的运行结果
    14 deco(test2)
    15 执行结果:
    16 in the test1
    17 the func run time is -3.010805130004883
    18 in the test2
    19 the func run time is -3.012805461883545
    View Code

    分析:改变了函数的调用方式,违反原则。

    b.返回值调用方式:func(),变成return func

     1 import time
     2 def deco(func):
     3     start_time = time.time()
     4     return func #返回执行结果,下面语句就不执行了
     5     stop_time = time.time()
     6     print("the func run time is %s" %(start_time-stop_time))
     7 def test1():
     8     time.sleep(3)
     9     print("in the test1")
    10 def test2():
    11     time.sleep(3)
    12     print("in the test2")
    13 test1 = deco(test1)
    14 test1()
    15 test2 = deco(test2)
    16 test2()
    17 
    18 执行结果:
    19 in the test1
    20 in the test2
    View Code

    分析:返回值调用不修改源代码和调用方式,但需求未实现。

    c.加了嵌套函数:函数中定义新函数,返回新函数的变量名=内存地址=函数名,把返回值赋予一个变量,执行变量即可得到结果

     1 import time
     2 def timer(func):#func=test1,把test1函数作为timer函数的参数传递进去
     3     def deco(): #函数timer中定义新函数deco,即为函数嵌套
     4         start_time = time.time()
     5         func() #func=test1,运行func(),即为运行test1()
     6         stop_time = time.time()
     7         print("the func run time is %s"%(start_time-stop_time))
     8     return deco #返回deco内存地址,即为高级函数
     9 def test1():
    10     time.sleep(3)
    11     print("in the test1")
    12 test2 = timer(test1) #把test1()函数的内存地址test1作为参数传递给timer函数
    13 test2() #执行test2()函数
    14 
    15 执行结果:
    16 in the test1
    17 the func run time is -3.010805130004883
    View Code

    d.装饰器

     1 import time
     2 def timer(func):
     3     def deco():
     4         start_time = time.time()
     5         func()
     6         stop_time = time.time()
     7         print("the fun run time is %s"%(start_time-stop_time))
     8     return deco
     9 
    10 @timer #给test1增加新功能
    11 def test1():
    12     time.sleep(3)
    13     print("in the test1")
    14 
    15 test1() #执行deco函数时,嵌套执行的是func()函数,即test1()=func()
    16 
    17 执行结果:
    18 in the test1
    19 the fun run time is -3.0118050575256348
    View Code

    若被修饰的函数test1带位置参数,会咋样?

     1 @timer
     2 def test2(name):
     3     time.sleep(2)
     4     print("in the test2",name)
     5 test2()
     6 
     7 执行结果:报错
     8 TypeError: test2() missing 1 required positional argument: 'name'
     9 分析:
    10 test2()相当于函数timer()中的func()函数,在嵌套函数deco()中执行时func()没有位置参数name,所以报错。
    View Code

    e.装饰器:举例说明带可变参数和不带参数

     1 import time
     2 def timer(func):
     3     def deco(*args,**kwargs):
     4         start_time = time.time()
     5         func(*args,**kwargs)
     6         stop_time = time.time()
     7         print("the fun run time is %s"%(stop_time-start_time))
     8     return deco
     9 
    10 @timer
    11 def test1():
    12     time.sleep(2)
    13     print("in the test1")
    14 @timer
    15 def test2(name,age):
    16     time.sleep(2)
    17     print("in the test2",name,age)
    18 
    19 test1()
    20 test2('alex',22)
    21 
    22 执行结果:
    23 in the test1
    24 the fun run time is 2.0124034881591797
    25 in the test2 alex 22
    26 the fun run time is 2.0124034881591797
    View Code

    总结:装饰器又叫语法糖。

    用途:公司有网站很多页面,一个页面一个函数,现在100个页面里有20个页面需要登录才能看到,所以在20个页面函数里加上验证功能才能看到。

    需求1:编写一个登陆认证程序,主页index不需要登录,用户自己的home和bbs需要登录

     1 #!/usr/bin/env python
     2 import time
     3 user,passwd = 'alex','abc123'
     4 def auth(func):
     5     def wrapper(*args,**kwargs):
     6         username = input("Username:").strip()
     7         password = input("Password:").strip()
     8 
     9         if user == username and passwd == password:
    10             print("33[32:1mGreat,user got it!33[0m")
    11             return func(*args,**kwargs)
    12         else:
    13             exit("33[31:1mInvalid username or password33[0m")
    14             #exit()
    15     return wrapper
    16 
    17 def index():
    18     print("Welcome to index page.")
    19 
    20 @auth
    21 def home():
    22     print("Great,home page got it!")
    23     return "from home"
    24 
    25 @auth
    26 def bbs():
    27     print("Great,bbs page got it!")
    28 
    29 index()
    30 home()
    31 bbs()
    32 
    33 执行结果:
    34 Welcome to index page.
    35 Username:alex #执行home()需要输入用户名和密码
    36 Password:abc123
    37 [32:1mGreat,user got it!
    38 Great,home page got it!
    39 Username:alex  #执行bbs时需要再次输入用户名和密码
    40 Password:abc123
    41 [32:1mGreat,user got it!
    42 Great,bbs page got it!
    View Code

    需求2,终极版:home实现本地认证,bbs实现ldap认证

     1 import time
     2 user,passwd = 'alex','abc123'
     3 def auth(auth_type):
     4     print("auth func:",auth_type)
     5     def out_wrapper(func):
     6         def wrapper(*args,**kwargs):
     7             print("wrapper func:",*args,**kwargs)
     8             if auth_type == "local":
     9                 username = input("Username:").strip()
    10                 password = input("Password:").strip()
    11 
    12                 if user == username and passwd == password:
    13                     print("33[32:1mGreat user got it!33[0m")
    14                     return func(*args,**kwargs)
    15                 else:
    16                     exit("33[31:1mInvaild username or password33[0m")
    17             elif auth_type == "ldap":
    18                 print("搞毛线ldap,不会")
    19         return wrapper
    20     return out_wrapper
    21 
    22 def index():
    23     print("Welcome to index page.")
    24 
    25 @auth(auth_type="local")#这句话相当于home() = wrapper(),接下来home才开始执行
    26 def home():
    27     print("Welcome to home page.")
    28     return "From home"
    29 
    30 @auth(auth_type="ldap")
    31 def bbs():
    32     print("Welcome to bbs page.")
    33 
    34 index()
    35 home()
    36 bbs()
    37 
    38 执行结果:
    39 auth func: local
    40 auth func: ldap
    41 Welcome to index page.
    42 wrapper func:
    43 Username:alex
    44 Password:abc123
    45 [32:1mGreat user got it!
    46 Welcome to home page.
    47 wrapper func:
    48 搞毛线ldap,不会
    View Code
  • 相关阅读:
    迅为iTOP4412开发板支持4G以上文件系统扩展
    迅为瑞芯微itop3399开发板Android8系统wifi移植
    centos 下安装显卡驱动步骤
    smarty函数转载
    jquery.qrcode二维码插件生成彩色二维码
    转 jquery插件241个jquery插件—jquery插件大全
    收集的jquery插件
    主机屋空间
    用过的php函数
    VeryMule网上商城
  • 原文地址:https://www.cnblogs.com/wolfs685/p/6725237.html
Copyright © 2011-2022 走看看