zoukankan      html  css  js  c++  java
  • ql的python学习之路-day9

    前言:本节主要学习装饰器

    一、装饰器

    定义:本质上是个函数,用来装饰其他函数;(就是为其他函数添加附加功能)

    原则:1.不能修改被装饰的函数的源代码

       2.不能修改被装饰的函数的调用方式

    以上两点可以总结出装饰器对被装饰的函数来说是完全透明的,因为装饰器不能修改原函数的源代码,被装饰的函数还是像往常一样继续运行。

    实现装饰器的知识储备:1.函数即‘变量’

               2.高阶函数

               3.嵌套函数

    可以理解成:高阶函数 + 嵌套函数 = 装饰器

    1.函数即‘变量’

    内存回收机制:数据存储在内存中,用变量名来引用;如果把内存比作一栋大厦,数据比作一个房间,变量名相当于门牌号,用门牌号来访问房间;如果删除了变量名,在一段时间内没有引用数据,python的内存回收机制就会回收数据。

    函数如同变量:函数和变量一样也有内存回收机制,在定义函数的时候相当于把函数体赋值给了函数名,在内存里面存储着函数体,然后用函数名来引用;匿名函数也是一样,在内存中存储lambda表达式,如果把lambda表达式赋值给一个变量名,就能用变量来引用lambda表达式。

    2.高阶函数

    满足下面任意一条就可以看做是高阶函数:

    a:把一个函数名当做实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)

    b:返回值中包含函数名(不修改函数的调用方式)

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:qinjiaxi
     4 import time
     5 
     6 def bar():
     7     time.sleep(3)
     8     print('in the test1')
     9 
    10 def test1(func):
    11     start_time = time.time()
    12     func()
    13     stop_time = time.time()
    14     print("time func run time is %s" % (stop_time-start_time))
    15 
    16 test1(bar)

    3.嵌套函数

    在一个函数体内定义一个函数,而不是在一个函数里面调用函数,这个叫做函数的嵌套。

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:qinjiaxi
     4 x = 2
     5 def grandpa():
     6     x = 1
     7     def father():
     8         x = 2
     9         def son():
    10             x = 3
    11             print(x)
    12         son()
    13     father()
    14 grandpa()

    返回值是3

    4.装饰器实例

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:qinjiaxi
     4 import time
     5 #timer是装饰器满足嵌套函数(函数里面定义一个函数),满足高阶函数(返回值有函数名)
     6 def timer(func):
     7     def deco(*args, **kwargs):
     8         start_time = time.time()
     9         func(*args, **kwargs)#run test1
    10         stop_time = time.time()
    11         print("the func run time is %s" % (stop_time - start_time))
    12     return deco
    13 @timer #test1 = timer(test1)#调用装饰器
    14 def test1():
    15     time.sleep(3)
    16     print("in the test1")
    17 test1()#这个不是上面这个test1函数,其实是运行deco这个内存地址

     5.装饰器实例升级版

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:qinjiaxi
     4 import time
     5 user, password = 'qinjiaxi', 'abc123'
     6 def auth(auth_type):
     7     print("auth func", auth_type)
     8     def out_wrapper(func):
     9         def wrapper(*args, **kwargs):
    10             print("wrapper func args", *args, **kwargs)
    11             if auth_type == "local":
    12                 username = input("Username:").strip()
    13                 passwd = input("Password:").strip()
    14                 if user == username and password == password:
    15                     print("33[32;1mUser has passed authentication33[0m")
    16                     res = func(*args,**kwargs)#from home
    17                     print("-----after authentication-----")
    18                     return res
    19                 else:
    20                     exit("33[31;1mInvalid username or password33[0m")
    21             elif auth_type == 'ldap':
    22                 print("sorry I do not know")
    23         return wrapper
    24     return out_wrapper
    25 
    26 
    27 def index():
    28     print("welcome to index page")
    29 
    30 @auth(auth_type='local')#home = wrapper /home = out_wrapper(home)
    31 def home():
    32     print("welcome to home page")
    33     return "from home"
    34 
    35 @auth(auth_type="ldap")#bbs = wrapper
    36 def bbs():
    37     print("welcome to bbs page")
    38 
    39 index()
    40 print(home())
    41 bbs()

     注:装饰器对于初学者来说还是比较难以理解的。实际多debug一下就会理解其中的原理,下面简单的分几个步骤剖析一下(拿上面的升级版实例来说明):

    1.当调用装饰器时(实例中的@auth(auth_type = ‘xxxx’))其实程序运行时先找到调用装饰器的位置,从装饰器里面一步一步的return出最里层的函数的内存地址,也就是函数名(实例中的wrapper)

    2.返回出最里层函数名后跳到最后面的调用函数部分(实例中最后三行)来调用函数(这个函数其实就是上面最里层的函数)

    3.然后执行装饰器最里层的函数,执行到res = func(*args, **kwargs)时候就是调用被装饰的函数

  • 相关阅读:
    考驾照的心得
    VS2005+ACCESS WEB程序出错数据访问权限错误的解决方法
    delphi开发回忆录——面向对象的基础,继承(续)
    用人不疑,疑人不用
    delphi开发回忆录——示例源码下载
    delphi开发回忆录——面向对象的基础,继承
    delphi开发回忆录——面向对象的基础,继承(续)
    delphi开发回忆录——示例源码下载
    考驾照的心得
    Win32 API消息函数:GetMessagePos
  • 原文地址:https://www.cnblogs.com/qinlangsky/p/9490706.html
Copyright © 2011-2022 走看看