zoukankan      html  css  js  c++  java
  • Python学习——02-Python基础——【6-函数闭包与装饰器】

    1.装饰器

    1. 什么是装饰器

    器即函数

    装饰即修饰,意指为其他函数添加新功能

    装饰器定义:本质就是函数,功能是为其他函数添加新功能

    2.装饰器需要遵循的原则

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

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

    3.实现装饰器知识储备

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

    4.高阶函数

    高阶函数定义:
    1.函数接收的参数是一个函数名

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

    3.满足上述条件任意一个,都可称之为高阶函数

    1.高阶函数示范

     1 def foo():
     2     print('我的函数名作为参数传给高阶函数')
     3 def gao_jie1(func):
     4     print('我就是高阶函数1,我接收的参数名是%s' %func)
     5     func()
     6 
     7 def gao_jie2(func):
     8     print('我就是高阶函数2,我的返回值是%s' %func)
     9     return func
    10 
    11 gao_jie1(foo)
    12 gao_jie2(foo)

    输出:

    我就是高阶函数1,我接收的参数名是<function foo at 0x00000191572D1F28>
    我的函数名作为参数传给高阶函数
    我就是高阶函数2,我的返回值是<function foo at 0x00000191572D1F28>

    2.把函数当做参数传给高阶函数

     1 #高阶函数应用1:把函数当做参数传给高阶函数
     2 import time
     3 def foo():
     4     print('from the foo')
     5 
     6 def timmer(func):
     7     start_time=time.time()
     8     func()
     9     stop_time=time.time()
    10     print('函数%s 运行时间是%s' %(func,stop_time-start_time))
    11 timmer(foo)
    12 #总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的执行方式是foo(),现在我们需要调用高阶函数timmer(foo),改变了函数的调用方式

    输出:

    from the foo
    函数<function foo at 0x000001DEFDDC1F28> 运行时间是0.0

    3.函数返回值是函数名

     1 #高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名
     2 import time
     3 def foo():
     4     print('from the foo')
     5 
     6 def timmer(func):
     7     start_time=time.time()
     8     return func
     9     stop_time=time.time()
    10     print('函数%s 运行时间是%s' %(func,stop_time-start_time))
    11 foo=timmer(foo)
    12 foo()
    13 #总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能

    输出:

    #高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名
    import time
    def foo():
        print('from the foo')
    
    def timmer(func):
        start_time=time.time()
        return func
        stop_time=time.time()
        print('函数%s 运行时间是%s' %(func,stop_time-start_time))
    foo=timmer(foo)
    foo()
    #总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能

    高阶函数总结
    1.函数接收的参数是一个函数名
      作用:在不修改函数源代码的前提下,为函数添加新功能,
      不足:会改变函数的调用方式
    2.函数的返回值是一个函数名
      作用:不修改函数的调用方式
      不足:不能添加新功能

    5.函数嵌套

    1 def father(name):
     2     print('from father %s' %name)
     3     def son():
     4         print('from son')
     5         def grandson():
     6             print('from grandson')
     7         grandson()
     8     son()
     9 
    10 father('林海峰')

    输出:

    from the foo

    6.闭包

    闭包:闭包(closure)是函数式编程的重要的语法结构。函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式)。在面向过程编程中,我们见到过函数(function);在面向对象编程中,我们见过对象(object)。函数和对象的根本目的是以某种逻辑方式组织代码,并提高代码的可重复使用性(reusability)。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。

    1 '''
     2 闭包:在一个作用域里放入定义变量,相当于打了一个包
     3 '''
     4 def father(name):
     5     def son():
     6         # name='alex'
     7         print('我爸爸是 [%s]' %name)
     8         def grandson():
     9             # name='wupeiqi'
    10             print('我爷爷是 [%s]' %name)
    11         grandson()
    12     son()
    13 
    14 father('caofu')

    输出:

    我爸爸是 [caofu]
    我爷爷是 [caofu]

     

     

    2.无参装饰器

    1.无参装饰器

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

    基本框架

    1 #这就是一个实现一个装饰器最基本的架子
    2 def timer(func):
    3     def wrapper():
    4         func()
    5     return wrapper

    加上参数

    1 def timer(func):
    2     def wrapper(*args,**kwargs):
    3         func(*args,**kwargs)
    4     return wrapper

    加上功能

    1 import time
    2 def timer(func):
    3     def wrapper(*args,**kwargs):
    4         start_time=time.time()
    5         func(*args,**kwargs)
    6         stop_time=time.time()
    7         print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time))
    8     return wrapper

    加上返回值

    1 import time
    2 def timer(func):
    3     def wrapper(*args,**kwargs):
    4         start_time=time.time()
    5         res=func(*args,**kwargs)
    6         stop_time=time.time()
    7         print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time))
    8         return res
    9     return wrapper

    使用装饰器

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

    语法糖@

    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))

    2.装饰器应用示例

     1 user_list=[
     2     {'name':'alex','passwd':'123'},
     3     {'name':'linhaifeng','passwd':'123'},
     4     {'name':'wupeiqi','passwd':'123'},
     5     {'name':'yuanhao','passwd':'123'},
     6 ]
     7 
     8 current_user={'username':None,'login':False}
     9 
    10 def auth_deco(func):
    11     def wrapper(*args,**kwargs):
    12         if current_user['username'] and current_user['login']:
    13             res=func(*args,**kwargs)
    14             return res
    15         username=input('用户名: ').strip()
    16         passwd=input('密码: ').strip()
    17 
    18         for index,user_dic in enumerate(user_list):
    19             if username == user_dic['name'] and passwd == user_dic['passwd']:
    20                 current_user['username']=username
    21 
    22                 current_user['login']=True
    23                 res=func(*args,**kwargs)
    24                 return res
    25                 break
    26         else:
    27             print('用户名或者密码错误,重新登录')
    28 
    29     return wrapper
    30 
    31 @auth_deco
    32 def index():
    33     print('欢迎来到主页面')
    34 
    35 @auth_deco
    36 def home():
    37     print('这里是你家')
    38 
    39 def shopping_car():
    40     print('查看购物车啊亲')
    41 
    42 def order():
    43     print('查看订单啊亲')
    44 
    45 print(user_list)
    46 # index()
    47 print(user_list)
    48 home()

    输出:

    [{'name': 'alex', 'passwd': '123'}, {'name': 'linhaifeng', 'passwd': '123'}, {'name': 'wupeiqi', 'passwd': '123'}, {'name': 'yuanhao', 'passwd': '123'}]
    [{'name': 'alex', 'passwd': '123'}, {'name': 'linhaifeng', 'passwd': '123'}, {'name': 'wupeiqi', 'passwd': '123'}, {'name': 'yuanhao', 'passwd': '123'}]
    用户名: 

    2.带参装饰器

     1 user_list=[
     2     {'name':'alex','passwd':'123'},
     3     {'name':'linhaifeng','passwd':'123'},
     4     {'name':'wupeiqi','passwd':'123'},
     5     {'name':'yuanhao','passwd':'123'},
     6 ]
     7 
     8 current_user={'username':None,'login':False}
     9 def auth(auth_type='file'):
    10     def auth_deco(func):
    11         def wrapper(*args,**kwargs):
    12             if auth_type == 'file':
    13                 if current_user['username'] and current_user['login']:
    14                     res=func(*args,**kwargs)
    15                     return res
    16                 username=input('用户名: ').strip()
    17                 passwd=input('密码: ').strip()
    18 
    19                 for index,user_dic in enumerate(user_list):
    20                     if username == user_dic['name'] and passwd == user_dic['passwd']:
    21                         current_user['username']=username
    22                         current_user['login']=True
    23                         res=func(*args,**kwargs)
    24                         return res
    25                         break
    26                 else:
    27                     print('用户名或者密码错误,重新登录')
    28             elif auth_type == 'ldap':
    29                 print('巴拉巴拉小魔仙')
    30                 res=func(*args,**kwargs)
    31                 return res
    32         return wrapper
    33     return auth_deco
    34 
    35 
    36 #auth(auth_type='file')就是在运行一个函数,然后返回auth_deco,所以@auth(auth_type='file')
    37 #就相当于@auth_deco,只不过现在,我们的auth_deco作为一个闭包的应用,外层的包auth给它留了一个auth_type='file'参数
    38 @auth(auth_type='ldap')
    39 def index():
    40     print('欢迎来到主页面')
    41 
    42 @auth(auth_type='ldap')
    43 def home():
    44     print('这里是你家')
    45 
    46 def shopping_car():
    47     print('查看购物车啊亲')
    48 
    49 def order():
    50     print('查看订单啊亲')
    51 
    52 # print(user_list)
    53 index()
    54 # print(user_list)
    55 home()

    输出:

    巴拉巴拉小魔仙
    欢迎来到主页面
    巴拉巴拉小魔仙
    这里是你家

    3.超时装饰器

    最近工作有点多,趁周末有空,继续分享我在学习和使用python过程中的一些小tips。

    有没有遇到过这样的事情:对数据库执行插入或更新操作,因为数据量大或其他原因,导致此次操作非常耗时,有时甚至等上好几个小时,也无法完成。很郁闷,怎么操作不超时啊?因为数据库配置时超时时间很长,并且有些操作又是需要很长时间的,所以不能修改默认的超时时间。

    因为客观条件不允许,我们不能靠数据库超时来终止此次操作,所以必须要在自己的方法逻辑模块里实现超时检测的功能。

    在python里有没有可以不用修改原来的方法内部逻辑,就能实现超时检测呢?肯定有啦,就是利用装饰器。装饰器是什么?在博客园找到了一篇介绍文章:函数和方法装饰漫谈(Function decorator)

    废话听完,我现在介绍主角出场:超时装饰器,timeout decorator。

    超时检测逻辑:启动新子线程执行指定的方法,主线程等待子线程的运行结果,若在指定时间内子线程还未执行完毕,则判断为超时,抛出超时异常,并杀掉子线程;否则未超时,返回子线程所执行的方法的返回值。

    在实现过程中,发现python默认模块里是没有方法可以杀掉线程的,怎么办呢?当然先问问google或百度,果然,keill thread这个关键词很热门,很快就搜索到我想要的东西了:"Kill a thread in Python",就是以下这个KThread类,它继承了threading.Thread,并添加了kill方法,让我们能杀掉它:

      1 import sys,threading,time
      2 
      3 
      4 class KThread(threading.Thread):
      5 
      6     """A subclass of threading.Thread, with a kill()
      7 
      8     method.
      9 
     10 
     11 
     12     Come from:
     13 
     14     Kill a thread in Python:
     15 
     16     http://mail.python.org/pipermail/python-list/2004-May/260937.html
     17 
     18     """
     19 
     20     def __init__(self, *args, **kwargs):
     21 
     22         threading.Thread.__init__(self, *args, **kwargs)
     23 
     24         self.killed = False
     25 
     26 
     27 
     28     def start(self):
     29 
     30         """Start the thread."""
     31 
     32         self.__run_backup = self.run
     33 
     34         self.run = self.__run      # Force the Thread to install our trace.
     35 
     36         threading.Thread.start(self)
     37 
     38 
     39 
     40     def __run(self):
     41 
     42         """Hacked run function, which installs the
     43 
     44         trace."""
     45 
     46         sys.settrace(self.globaltrace)
     47 
     48         self.__run_backup()
     49 
     50         self.run = self.__run_backup
     51 
     52 
     53 
     54     def globaltrace(self, frame, why, arg):
     55 
     56         if why == 'call':
     57 
     58           return self.localtrace
     59 
     60         else:
     61 
     62           return None
     63 
     64 
     65 
     66     def localtrace(self, frame, why, arg):
     67 
     68         if self.killed:
     69 
     70           if why == 'line':
     71 
     72             raise SystemExit()
     73 
     74         return self.localtrace
     75 
     76 
     77 
     78     def kill(self):
     79 
     80         self.killed = True
     81 
     82 
     83 
     84 class Timeout(Exception):
     85 
     86     """function run timeout"""
     87 
     88 
     89 
     90 def timeout(seconds):
     91 
     92     """超时装饰器,指定超时时间
     93 
     94     若被装饰的方法在指定的时间内未返回,则抛出Timeout异常"""
     95 
     96     def timeout_decorator(func):
     97 
     98         """真正的装饰器"""
     99 
    100 
    101 
    102         def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs):
    103 
    104             result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs))
    105 
    106 
    107 
    108         def _(*args, **kwargs):
    109 
    110             result = []
    111 
    112             new_kwargs = { # create new args for _new_func, because we want to get the func return val to result list
    113 
    114                 'oldfunc': func,
    115 
    116                 'result': result,
    117 
    118                 'oldfunc_args': args,
    119 
    120                 'oldfunc_kwargs': kwargs
    121 
    122             }
    123 
    124             thd = KThread(target=_new_func, args=(), kwargs=new_kwargs)
    125 
    126             thd.start()
    127 
    128             thd.join(seconds)
    129 
    130             alive = thd.isAlive()
    131 
    132             thd.kill() # kill the child thread
    133 
    134             if alive:
    135 
    136                 raise Timeout(u'function run too long, timeout %d seconds.' % seconds)
    137 
    138             else:
    139 
    140                 return result[0]
    141 
    142         _.__name__ = func.__name__
    143 
    144         _.__doc__ = func.__doc__
    145 
    146         return _
    147 
    148     return timeout_decorator
    149 
    150 
    151 @timeout(5)
    152 
    153 def method_timeout(seconds, text):
    154 
    155     print('start', seconds, text)
    156 
    157     time.sleep(seconds)
    158 
    159     print('finish', seconds, text)
    160 
    161     return seconds
    162 
    163 
    164 method_timeout(6,'asdfasdfasdfas')
  • 相关阅读:
    gulp通过http-proxy-middleware开启反向代理,实现跨域
    一些我常用的css 或者 js
    四舍五入
    生成 SSH 公钥
    对象转为数组 用lodash
    廖雪峰的官方网站
    window对象
    字符串
    简单得日期
    LeetCode 113. Path Sum II 20170705 部分之前做了没写的题目
  • 原文地址:https://www.cnblogs.com/caofu/p/8757627.html
Copyright © 2011-2022 走看看