zoukankan      html  css  js  c++  java
  • Python-Day 5-装饰器

    一、定义

    1、装饰器:本质是函数。

    2、功能:用来装饰其他函数,顾名思义就是,为其他的函数添加附件功能的。

    3、原则:不能修改被装饰函数的源代码、不能修改被装饰函数的调用方式

    4、函数即"变量", 高阶函数+嵌套函数 => 装饰器

    def test():
        print("LOVE")
    #正确写法,没有修改源码
    def test1():
        print("LOVE ME")
    #错误写法,不能修改源码 def test1(): print("LOVE ME") test() #调用 test1()

     二、函数即变量

    1、python的内存机制

    在python解释器中,有一个概念叫做引用基数,例如,x=1这个b变量,先在内存当中把1这个值存放下来,这个x其实就是1的门牌号,x=1就是对1的一次引用。

    python等到1所对应的门牌号都没有了,就会把1给清掉,这个也是python的内存回收机制。 

    python用del去清理门牌号,就是对1的值引用的变量,del  x就表示清理掉1对应的x的门牌号。如果x没有被del,则x永远不会被删除,除非程序结束了。del删除的不是1,只是把门牌号x删除了,定期刷新时,发现1没有被其他门牌号引用了,1才会被清掉。

    #变量
    x = 1
    #函数
    def test():
        pass
    

      

    2、函数在内存的表现形式

    ①test函数在fex函数之后定义

    def test():
        print("in test")
        fex()
    
    def fex():
        print("in fex")
    
    test()
    
    #结果
    in test
    in fex 

    test函数在fex函数之前定义

    def fex():
        print("in fex")
    
    def test():
        print("in test")
        fex()
    test()
    #结果 in test in fex 

    上面两种写法,输出结果是一样的

    test函数在fex函数之后声明


    def test():
    print("in test")
    fex()

    test()

    def fex():
    print("in fex")
    #结果 Traceback (most recent call last): File "/Users/bianbian/PycharmProjects/test/test10.py", line 5, in <module> test() NameError: name 'test' is not defined

    因为在执行test函数时,当调用fex函数时,fex还函数还定义,所以报错。

    三、高阶函数

    实现高阶函数的条件:把一个函数名当做实参传给另外一个函数,且返回值中包含函数名

    1、把一个函数名当做实参传给另外一个函数

    import time
    def fex():
        time.sleep(3)
        print("in the fex")
    def test(func):
        print(func)
        start_time = time.time()
        func()
        stop_time = time.time()
        print("the func run the is %s" % (stop_time - start_time))
    #没有修改fex的代码
    test(fex) #把fex函数名当做实参传到test中
    #结果
    <function fex at 0x10df3b268>
    in the fex
    the func run the is 3.0029611587524414
    

     作用:在不修改被装饰函数源代码的情况下为其添加功能

    2、返回值中包括函数名

    import time
    def fex():
        time.sleep(3)
        print("in the fex")
    def test1(func):
        print(func)
        return(func) #返回函数的内存地址
    
    test=test1(fex)
    fex()
    #没有改变fex函数的调用方式
    #结果
    <function fex at 0x1090ab268>
    in the fex
    

     作用:不修改函数调用方式

    四、嵌套函数

    在一个函数的函数体内,用def 去声明一个函数,而不是去调用其他函数,称为嵌套函数。

    def fex():
        print("in fex")
        def fun():
            #在fex函数体内声明一个函数fun
            print("in fun")
        fun()
    fex()
    

    变量的作用域:从里往外找,一层一层的的找。 

    x=0
    def test():
        x=1
        def test1():
            x=2
            def test2():
                x=3
                print(x)
            test2()
        test1()
    test()
    #结果
    3
    

     五、装饰器

    装饰器实现的条件:高阶函数+嵌套函数 =>装饰器

    import time
    #定义内置函数
    def timmer(func): #timmer(test) func=test
        def fex():
            start_time=time.time()
            func() #run test()
            stop_time=time.time()
            print("the func run time is %s" %(start_time-stop_time))
        return fex
    #装饰test函数
    @timmer  # 相当于test = timmer(test)
    def test():
        time.sleep(3)
        print("in the test")
    #直接执行test函数
    test()
    
    #结果
    in the test
    the func run time is -3.0014219284057617 

    执行步骤:

    1. 执行timmer函数,timmer(test) 返回值赋值给test变量,即test=timmer(test)
    2. 此时的test的值是执行timmer函数返回值fex,即test=fex
    3. 所以执行test,其实就是执行的是fex函数,test()其实就是执行fex函数。

     1、执行函数带参数

    import time
    #定义内置函数
    def timmer(func): #timmer(test) func=test
        def fex():
            start_time=time.time()
            func() #run test()
            stop_time=time.time()
            print("the func run time is %s" %(start_time-stop_time))
        return fex
    #装饰test1函数
    
    @timmer  # 相当于test1 = timmer(test1)
    def test1(age,name):
        print("name:%s,age:%s"%(age,name))
    #直接执行test函数
    test1()
    #结果
    Traceback (most recent call last):
      File "/Users/bianbian/PycharmProjects/test/test11.py", line 16, in <module>
        test1()
      File "/Users/bianbian/PycharmProjects/test/test11.py", line 6, in fex
        func() #run test()
    TypeError: test1() missing 2 required positional arguments: 'age' and 'name'
    

     因为这边执行的test1函数其实就是执行的fex函数,fex函数体内的func()其实就是执行test1函数,但是,test1需要传入name和age两个参数,所以报错。那怎么解决呢?传入参数!

       但是你又不能确定传入几个参数,所以用非固定参数传参

    import time
    #定义内置函数
    def timmer(func): #timmer(test) func=test
        def fex(*args,**kwargs):#传入非固定参数
            start_time=time.time()
            func(*args,**kwargs) #传入非固定参数
            stop_time=time.time()
            print("the func run time is %s" %(start_time-stop_time))
        return fex
    
    #不带参数
    @timmer
    def test1(): # 相当于test1 = timmer(test1)
        time.sleep(3)
        print("in the test1")
    #带参数
    @timmer  # test2 = timmer(test2)
    def test2(age,name):
        print("name:%s,age:%s"%(age,name))
    #调用
    test1()
    test2("bianbian",18)
    
    #结果
    #test1
    in the test1
    the func run time is -3.0028131008148193
    #test2
    name:bianbian,age:18
    the func run time is -1.5020370483398438e-05
    

     2、执行函数有返回值

    如果,被调函数的有返回值??

    def timmer(func): #timmer(test) func=test
        def fex(*args,**kwargs):#传入非固定参数
            res=func(*args,**kwargs) #传入非固定参数
            return res
        return fex
    
    #不带参数
    @timmer
    def test1(): # 相当于test1 = timmer(test1)
        print("in the test1")
        return "from the test1"  # 执行函数test1有返回值
    res = test1()
    print(res)
    
    #结果
    in the test1
    from the test1
    

     通过上面的例子,可以看出,就是在内置函数中把传入参数的执行结果赋给res,然后再返回res变量。

    3、带参数的装饰器

    之前装饰器都是没有带参数的,但是访问不到页面时,你用的验证的方式来源不同,这时你该怎么办?  

    name,password="bianbian","bfj123321"
    def auth(auth_type):#传递装饰器的参数
        print("auth_type",auth_type)
        def outer_wrapper(func):# 将被装饰的函数作为参数传递进来
            def wrapper(*args,**kwargs):# 将被装饰的函数作为参数传递进来
                print("wrapper func args",*args,**kwargs)
                username=input("Username:").strip()
                password=input("Password:").strip()
                if auth_type == "local":
                    if name == username and password == password:
                        print("%s has passed authentication"%name)
                        res=func(*args,**kwargs)
                        print("--------after authentication")
                        return res
                    else:
                        exit("Invalid username or password")
                elif auth_type == "ldap":
                    pass
            return wrapper
        return outer_wrapper
    def index():
        print("Welcome to index")
    @auth(auth_type="local") #带参数装饰器
    def home():
        print("Welcome to home page")
        return "from home"
    @auth(auth_type="ldap") #带参数装饰器
    def bbs():
        print("Welcome to bbs page")
    index()
    home()
    bbs()
    

     结果:

    可以看出,执行步骤:

    1. outer_wrapper = auth(auth_type="local")
    2. home = outer_wrapper(home)
    3. home()

    所以这个函数的作用分别是:

    1. auth(auth_type) 传递装饰器的参数
    2. outer_wrapper(func) 把函数当做实参传递进来
    3. wrapper(*args,**kwargs) 真正执行装饰的函数
     
     

     

  • 相关阅读:
    POJ 1015 Jury Compromise【DP】
    POJ 1661 Help Jimmy【DP】
    HDU 1074 Doing Homework【状态压缩DP】
    HDU 1024 Max Sum Plus Plus【DP,最大m子段和】
    占坑补题。。最近占的坑有点多。。。
    Codeforces 659F Polycarp and Hay【BFS】
    Codeforces 659E New Reform【DFS】
    Codeforces 659D Bicycle Race【计算几何】
    廖大python实战项目第四天
    廖大python实战项目第三天
  • 原文地址:https://www.cnblogs.com/bianfengjie/p/10839410.html
Copyright © 2011-2022 走看看