zoukankan      html  css  js  c++  java
  • python装饰器,细致讲解

    1.无参装饰器

    1.储备知识

    1. *args,**kwargs

      def index(x,y):
         print(x,y)

      def wrapper(*args,**kwargs):#接收参数
         func(*args,**kwargs)#将参数打散
    2. 名称空间与作用域:名称空间的“嵌套”是在函数定义阶段,即检测语法的时候确定的

    3. 函数对象:

      • 可以把函数当做参数传入

      • 可以把函数当做返回值返回

    4. 函数的嵌套定义

      def outter(func):
         def wrapper():
             pass
         return wrapper
    5. 闭包函数

      • 函数B在函数A内部,并且函数B调用外层函数作用域的变量,那么函数B就是闭包函数

      • def funcA():
           x=111
           def funcB():
               x
           return funcB
    6. 传递函数的方式

      1. 通过参数的形式为函数传值

      2. 通过闭包的方式为函数传值

    2.装饰器

    1. 什么是装饰器

      • 定义一个函数,该函数在不修改原函数代码并且不改变调用方式的前提现,为被装饰的对象增加额外的功能

    2. 为何要用装饰器

      • 开放封闭原则

        • 开放:指的是对拓展功能是开放的

        • 封闭:指的是对修改源代码是封闭的

    3.得到装饰器思路

    需求:在不修改index函数源代码以及调用方式的情况下为其添加统计时间的功能

    def index(x,y):
       time.sleep(3)
       print('index %s %s'%(x,y))
    index(111,222)
    index(111,y=222)
    index(x=111,y=222)

    方案一:直接在index函数内加统计时间的代码

    import time
    def index(x,y):
       start = time.time()
       time.sleep(3)
       print('index %s %s'%(x,y))
       stop = time.time()
       print(stop-start)
       
    index(111,333)

    问题:没有修改代码的调用方式,但是修改了源代码,方案一失败

     

    方案二:在函数调用的时候添加统计时间的代码

    def index(x,y):
       time.sleep(3)
       print('index %s %s'%(x,y))
       
    start = time.time()
    index(111,222)
    stop = time.time()
    print(stop-start)

    start = time.time()
    index(333,444)
    stop = time.time()
    print(stop-start)

    start = time.time()
    index(555,666)
    stop = time.time()
    print(stop-start)

    问题:没有修改index的源代码,也没有修改调用方式,并且加上了新功能,但是代码冗余。方案二失败

     

    方案三:将方案二中冗余的代码部分写成函数

    def index(x,y):
       time.sleep(3)
       print('index %s %s'%(x,y))
       
    def swapper():    
       start = time.time()
       index(111,222)
       stop = time.time()
       print(stop-start)
       
    swapper()

    问题:解决了代码冗余问题,但是函数的调用方式发生改变。方案三失败

    方案三优化一:将index的参数写活

    def index(x, y):
       time.sleep(3)
       print('index %s %s' % (x, y))
       
    def swapper(*args,**kwargs):
       start = time.time()
       index(*args,**kwargs)
       stop = time.time()
       print(stop - start)

    swapper(2222,54544)

    方案三优化二:在优化一的基础上把被装饰的对象写活,原来只能装饰index

    def index(x,y,z):
       time.sleep(3)
       print('index %s %s %s' %(x,y,z))

    def home(name):
       time.sleep(2)
       print('welcome %s to home page' %name)


    def outter(func):
       # func = index的内存地址
       def wrapper(*args,**kwargs):
           start=time.time()
           func(*args,**kwargs) # index的内存地址()
           stop=time.time()
           print(stop - start)
       return wrapper

    index=outter(index) # index=wrapper的内存地址
    home=outter(home) # home=wrapper的内存地址

    方案三优化三:给wrapper添加返回值,达到以假乱真

    def index(x,y,z):
       time.sleep(3)
       print('index %s %s %s' %(x,y,z))

    def home(name):
       time.sleep(2)
       print('welcome %s to home page' %name)

    def outter(func):
       def wrapper(*args,**kwargs):
           start=time.time()
           res=func(*args,**kwargs)
           stop=time.time()
           print(stop - start)
           return res
       return wrapper
    # 偷梁换柱:home这个名字指向的wrapper函数的内存地址
    # home=outter(home)
    #
    #
    # res=home('egon') # res=wrapper('egon')
    # print('返回值--》',res)

    4.语法糖

    import time

    装饰器
    def timmer(func):
       def wrapper(*args,**kwargs):
           start=time.time()
           res=func(*args,**kwargs)
           stop=time.time()
           print(stop - start)
           return res
       return wrapper


    # 在被装饰对象正上方的单独一行写@装饰器名字
    # @timmer # index=timmer(index)
    def index(x,y,z):
       time.sleep(3)
       print('index %s %s %s' %(x,y,z))

    # @timmer # home=timmer(ome)
    def home(name):
       time.sleep(2)
       print('welcome %s to home page' %name)


    index(x=1,y=2,z=3)
    home('egon')

    2.有参装饰器

    1.知识储备

    • 由于语法糖@的限制,outter函数只能有一个参数,并且该参数只能接受被装饰对象的内存地址

    def outter(func):
       # func = 被装饰函数的内存地址
       def wrapper(*args,**kwargs):
           res = func(*args,**kwargs)
           return res
       return wrapper

    @outter #index=outter(index) ==> index=wrapper
    def index(x,y):
       print(x,y)
    • index被装饰后(偷梁换柱之后)

      • index的参数什么样子,wrapper的参数就应该什么样子

      • index的返回值什么样子,wrapper的返回值就应该什么样子

      • index的属性什么样子,wrapper的属性就应该什么样子==》from functools import wraps

     

    2.有参装饰器

    def auth(db_type):
       def deco(func):
           def wrapper(*args, **kwargs):
               name = input('your name>>>: ').strip()
               pwd = input('your password>>>: ').strip()

               if db_type == 'file':
                   print('基于文件的验证')
                   if name == 'egon' and pwd == '123':
                       res = func(*args, **kwargs)  # index(1,2)
                       return res
                   else:
                       print('user or password error')
               elif db_type == 'mysql':
                   print('基于mysql的验证')
               elif db_type == 'ldap':
                   print('基于ldap的验证')
               else:
                   print('不支持该db_type')
           return wrapper
       return deco
    @auth(db_type='file')  # @deco # index=deco(index) # index=wrapper
    def index(x, y):
       print('index->>%s:%s' % (x, y))

    @auth(db_type='mysql')  # @deco # home=deco(home) # home=wrapper
    def home(name):
       print('home->>%s' % name)
       
    @auth(db_type='ldap')  # 账号密码的来源是ldap
    def transfer():
       print('transfer')

    3.有参装饰器模板

    def 有参装饰器(x,y,z):
       def outter(func):
           def wrapper(*args, **kwargs):
               res = func(*args, **kwargs)
               return res
           return wrapper
       return outter

    @有参装饰器(1,y=2,z=3)
    def 被装饰对象():
       pass

     

  • 相关阅读:
    实践出真知关于ios项目重命名的实践 (xcode 4.3.1) ,以及svn 导出项目命令
    解决error: linker command failed with exit code 1类似的错误
    关于对ios 目录路径的理解
    UITableView 隔行换色 选中背景色 取消选中颜色 返回后显示正常颜色
    NSLog的常用格式说明小释
    app打包总结 以及 提交app审核过程
    UIView圆角
    substringToIndex substringFromIndex
    ios 判断文字高度,适用于tableview的自定义高度
    [转]android解析XML总结
  • 原文地址:https://www.cnblogs.com/shi-py-rengongzhineng/p/13908401.html
Copyright © 2011-2022 走看看