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

    一,装饰器的概念

    器即函数

    装饰即修饰,顾名思义就是为其他函数添加新功能

    装饰器的定义:装饰器本质上就是一个函数,这个函数接收其他函数做为参数,并将以一个新的修改后的函数进行替换。装饰器的应用场景就是对

    多个函数提供在其之前,之后或周围进行调用的通用代码

    二,装饰器需要遵循的原则

    1,不修改被装饰函数的源代码(开放封闭原则)

    2,为被装饰函数添加新功能后,不修改被装饰器的调用方式

    三,上面刚刚有写到装饰器本身就是函数,只是这个函数的功能比普通函数的功能要强大很多,那么一个函数怎样才能是一个装饰器呢

    装饰器=高阶函数+函数嵌套+闭包

    以前在博客中有写过什么是高阶函数,函数嵌套,现在我们在来回顾一下

    3.1高阶函数的定义

    3.1.1函数接收的参数是一个函数名

    3.1.2函数的返回值是一个函数名

    3.1.3满足以上条件任意一个,都可以称之为高阶函数

     1 def foo():
     2     print('我的函数名做为高阶函数的参数,传给高阶函数')
     3 
     4 def test_one(func):
     5     print('我是高阶函数1,我接收的参数是%s'%func)
     6     func()
     7 
     8 def test_two(func):
     9     print('我是高阶函数2,我的返回值是%s' %func)
    10     return func
    11 
    12 test_one(foo)
    13 ######执行结果#########
    14 #我是高阶函数1,我接收的参数是<function foo at 0x0000000001140048>
    15 #我的函数名做为高阶函数的参数,传给高阶函数
    16 
    17 test_two(foo)
    18 ######执行结果#########
    19 #我是高阶函数2,我的返回值是<function foo at 0x00000000006F0048>
     1 #高阶函数应用1:把函数名当做参数传给高阶函数
     2 #我们来计算一下foo这个函数执行花了多长时间
     3 
     4 import time
     5 def foo():
     6     time.sleep(1)
     7     print('我是函数foo,我的运行时间是多久')
     8 
     9 def test(func):
    10     '''
    11     计算foo这个函数运行时间
    12     :param func: 将foo这个函数作为参数,计算运行时间
    13     :return:
    14 
    15     '''
    16     start_time = time.time()
    17     func()
    18     stop_time = time.time()
    19     print('函数foo的运行时间是%s' % (stop_time - start_time))
    20 
    21 test(foo)
    22 
    23 #########执行结果#######
    24 #我是函数foo,我的运行时间是多久
    25 #函数foo的运行时间是1.0000572204589844
    26 
    27 #总结:在这个示例中,我们虽然为foo增加了计算运行时间的功能,但是foo原来的执行
    28 方式是foo(),现在我们需要调用高阶函数test(foo),改变了函数的调用方式
     1 #高阶函数应用2:把函数名当作参数传给高阶函数,高阶函数直接返回函数名
     2 
     3 import time
     4 def foo():
     5     time.sleep(1)
     6     print('我是函数foo,我的运行时间是多久')
     7 
     8 def test(func):
     9     '''
    10     计算foo这个函数运行时间
    11     :param func: 将foo这个函数作为参数,计算运行时间
    12     :return:
    13 
    14     '''
    15     start_time = time.time()
    16     return func
    17     stop_time = time.time()
    18     print('函数%s的运行时间是%s' % (func,stop_time - start_time))
    19     
    20 foo = test(foo)
    21 foo()
    22 
    23 ######执行结果########
    24 #我是函数foo,我的运行时间是多久
    25 
    26 
    27 #总结:这次执行我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能

    高阶函数总结:

    1,函数接收的参数是一个函数名

      作用:在不修改函数源代码的前提下,为函数添加新功能

      不足:会改变函数的调用方式

    2,函数的返回值是一个函数名

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

      不足:不能添加新功能

    3.2 函数嵌套

     1 user_name = 'jack'
     2 def test_one(name):
     3     print('my name is %s' %name)
     4     def test_two():
     5         name = 'zcy'
     6         print('test-two:%s' %name)
     7         def test_three():
     8             print('test_three',name)
     9         test_three()
    10     test_two()
    11 test_one(user_name)
    12 
    13 #########执行结果######
    14 #my name is jack
    15 #test-two:zcy
    16 #test_three zcy

    3.3闭包

     1 def test_one(name):
     2     '''
     3     闭包:在一个作用域里放入定义变量,相当于打了一个包
     4     :param name:
     5     :return:
     6     '''
     7     print('my name is %s' %name)
     8     def test_two():
     9         name = 'zcy'
    10         print('test-two:%s' %name)
    11         def test_three():
    12             print('test_three',name)
    13         test_three()
    14     test_two()
    15 test_one('laiying')
    16 
    17 #########执行结果#########
    18 #my name is laiying
    19 #test-two:zcy
    20 #test_three zcy

    四.无参装饰器

    无参装饰器=高阶函数+函数嵌套

    接下来我们开始创建装饰器

    我们先来创建一个最简单的装饰器,

     1 def test(func):
     2     return func
     3 
     4 @test
     5 def foo(name):
     6     print('My name is %s' %name)
     7 foo('laiying')
     8 
     9 #它和下面的过程类似
    10 
    11 def test(func):
    12     return func
    13 
    14 def foo(name):
    15     print('My name is %s' % name)
    16 foo = test(foo)
    17 
    18 #这个装饰器没什么用,但是可以正常运行,只不过它什么都不做

    语法糖@

    1  @timer  #@timer就等同于cal=timer(cal)
    2  def cal(array):
    3      res=0
    4      for i in array:
    5          res+=i
    6      return res
    7  
    8  cal(range(10))

    接下来我们有一个要求,比如视频刚上线初期,为了吸引用户,你们采取了免费政策,所有视频免费观看,迅速吸引了一大批用户,免费一段时间后,每天巨大的带宽费用公司承受不了了,所以准备对比较受欢迎的几个版块收费,其中包括“欧美” 和 “日韩”专区。

    接下来要这样才能实现这个要求呢

    思路:想收费得先让其进行用户认证,认证通过后,再判定这个用户是否是VIP付费会员就可以了,是VIP就让看,不是VIP就不让看就行了

    注意事项:在我们要修改代码前,一定要遵循软件开发原则中的一个“开发-封闭”原则,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:

    封闭:已实现的功能代码块

    开放:对扩展开发

    user_dic = [
        {'name':'laiying','pwd':123},
        {'name':'zcy','pwd':123},
        {'name':'alex','pwd':123},
        {'name':'jack','pwd':123},
    ]
    login_list = {'username':None,'login':False}
    username = input('请输入您的用户名:')
    paswd = int(input('请输入您的密码:'))
    def foo(func): # func = jd_index def test_one(*args,**kwargs): # jd_index(name) args='laiying' if login_list['username'] and login_list['login']: res = func(*args,**kwargs) # 4,func是foo的一个形式参数,这个形式参数对应的实际参数是jd_index这个函数 #所以现在所执行就是在调用jd_index这个函数 return res #将jd_index这个函数的执行结果返回给test_one,谁调用就返回给谁 for i in user_dic: if username == i['name'] and paswd == i['pwd']: login_list['username'] = username login_list['login'] = True print('恭喜您登录成功') result = func(*args,**kwargs) # 与(4)同理,运行jd_index return result else: print('您的用户名或者密码错误,请重新输入') return test_one # 2 将test_one这个函数名retrun给 foo

    @foo # 1. 开始调用foo这个装饰器,并将调用foo装饰器的这个函数(jd_index),做为参数传给foo # jd_index = foo(jd_index) def jd_index(name): print('hi %s! 您好,欢迎您登录xx首页'%name) return '执行成功。哈哈哈哈哈哈哈' # 5 ,这个return的结果是jd_index这个函数的一个返回值 jd_index(username) # 3,执行jd_index()就等于在执行foo()(),因为在第一步@foo的时候jd_index = foo(jd_index),相当于             #foo这个函数的执行结果从新赋值给了jd_index,所以现在执行jd_index,其实在执行foo这个函数的一个执行结果,而这个             #foo的执行就是return test_one 这个返回的test_one函数的内存地址,所以现在执行的就是test_one这个函数的内存地址,             #就是在执行test_one这个函数了 @foo def america(): print('----欧美专区----') america() @foo def japan(): print('----日韩专区----') japan()

    五,有参装饰器

     1 user_dic = [
     2     {'name':'laiying','pwd':123},
     3     {'name':'zcy','pwd':123},
     4     {'name':'alex','pwd':123},
     5     {'name':'jack','pwd':123},
     6 ]
     7 login_list = {'username':None,'login':False}
     8 username = input('请输入您的用户名:')
     9 paswd = int(input('请输入您的密码:'))
    10 def auth(auth_type='file'):
    11     def foo(func):  # func = id_index
    12         def test_one(*args,**kwargs):  
    13             if auth_type == 'file':
    14                 if login_list['username'] and login_list['login']:
    15                     res = func(*args,**kwargs)  
    16                                                 
    17                     return res 
    18 
    19                 for i in user_dic:
    20                     if username == i['name'] and paswd == i['pwd']:
    21                         login_list['username'] = username
    22                         login_list['login'] = True
    23                         print('恭喜您登录成功')
    24                         result  = func(*args,**kwargs)  
    25                         return result
    26                 else:
    27                     print('您的用户名或者密码错误,请重新输入')
    28             elif auth_type == 'ldap':
    29                 print('你现在选择的类型是日韩板块。。。')
    30                 result = func(*args,**kwargs)
    31                 return result
    32             else:
    33                 print('欢迎您选择大陆板块')
    34                 result = func(*args, **kwargs)
    35                 return result
    36 
    37         return test_one  
    38     return foo
    #auth(auth_type='file')就是在运行一个函数,然后返回foo,所以@auth(auth_type='file')
    #就相当于@foo,只不过现在,我们的foo作为一个闭包的应用,外层的包auth给它留了一个auth_type='file'参数
    39 @auth()  
    41 def jd_index(name):
    42     print('hi %s! 您好,欢迎您登录xx首页'%name)
    43     return '执行成功。哈哈哈哈哈哈哈'  
    44 jd_index(username) 
    45 
    49 
    50 @auth(auth_type='file')
    51 def america():
    52     print('----欧美专区----')
    53 
    54 america()
    55 @auth(auth_type='ldap')
    56 def japan():
    57     print('----日韩专区----')
    58 japan()
  • 相关阅读:
    Git`s Operation
    从volatile说到,i++原子操作,线程安全问题
    sql中的几种删除方式
    Hibernate&MyBatis different
    集合问答
    Data Struct and Data Type
    Hash table and application in java
    idea`s shortcut key
    001--idea第一个报错JNI报错
    recyclebin
  • 原文地址:https://www.cnblogs.com/YingLai/p/6144920.html
Copyright © 2011-2022 走看看