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) 真正执行装饰的函数
     
     

     

  • 相关阅读:
    第一个自己独立开发并发布的软件
    第一个JavaWeb项目体验
    今天开博
    Mongoid Paging and Iterating Over Large Collections
    图片格式瞎扯淡
    是时候用Coffeescript了
    Mac 小技巧
    印度见闻札记
    作为开发人员,您应该尊重默认行为
    Java 注解(Annoation)学习笔记
  • 原文地址:https://www.cnblogs.com/bianfengjie/p/10839410.html
Copyright © 2011-2022 走看看