zoukankan      html  css  js  c++  java
  • python4

    一、装饰器

          装饰器本质上也是函数,其功能是为被装饰的函数添加附加功能。装饰器的使用原则:(1)不能修改被装饰函数的源代码;(2)不能修改被装饰函数的调用方式,总之,装饰器对被装饰函数来说是透明的。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

         1、预备知识:

         (1)高阶函数:把一个函数名当作实参传递给另一个函数,返回值中包含函数名

         (2)嵌套函数:在一个函数体内声明一个函数,不是只调用一个函数

         (3)装饰器=高阶函数+嵌套函数

        2. 简单装饰器

    假如要统计一个函数的执行时间,我们可以写一个统计时间的函数,然后将被统计的函数作为参数传递

    复制代码
     1 import time
     2 def bar():
     3     time.sleep(3)
     4     print('in the bar')
     5 def test1(func):
     6     start_time=time.time()
     7     func()
     8     stop_time = time.time()
     9     print('the func run time is %s' % (stop_time - start_time))
    10 test1(bar)
    复制代码

    运行结果:

    in the bar
    the func run time is 3.000171661376953

    但是这样的话,我们每次都要将一个函数作为参数传递给test1函数。改变了函数调用方式,之前执行业务逻辑时,执行运行bar(),但是现在不得不改成test1(bar)。此时就要用到装饰器。我们就来想想办法不修改调用的代码;如果不修改调用代码,也就意味着调用bar()需要产生调用test1(bar)的效果。我们可以想到将test1赋值给bar,但是test1似乎带有一个参数……想办法把参数统一吧!如果test1(bar)不是直接产生调用效果,而是返回一个与foo参数列表一致的函数的话……就很好办了,将test1(bar)的返回值赋值给bar,然后,调用bar()的代码完全不用修改!

    复制代码
     1 import time
     2 def timmer(func):
     3     def deco():
     4         start_time=time.time()
     5         func()
     6         stop_time=time.time()
     7         print('the func run time is %s'%(stop_time-start_time))
     8     return deco
     9 
    10 def bar():
    11     time.sleep(3)
    12     print('in the bar')
    13 bar=timmer(bar)
    14 bar()
    复制代码

    运行结果:

    in the bar
    the func run time is 3.000171661376953

    函数timmer就是装饰器,它把执行真正业务方法的func包裹在函数里面,看起来像bar被timmer装饰了。如果我们要定义函数时使用装饰器,避免使用赋值语句bar=timmer(bar),要用到装饰器的语法糖@

    复制代码
     1 import time
     2 def timmer(func):
     3     def deco():
     4         start_time=time.time()
     5         func()
     6         stop_time=time.time()
     7         print('the func run time is %s'%(stop_time-start_time))
     8     return deco
     9 @timmer
    10 def bar():
    11     time.sleep(3)
    12     print('in the bar')
    13 bar()
    复制代码

    运行结果:

    in the bar
    the func run time is 3.000171661376953

    这样,我们就提高了程序的可重复利用性,当其他函数需要调用装饰器时,可以直接调用。装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。

         3.带有参数的装饰器
    如果要装饰的函数带有参数时
    复制代码
     1 import time
     2 def timmer(func):
     3     def deco(*arg,**kwarg):
     4         start_time=time.time()
     5         func(*arg,**kwarg)
     6         stop_time=time.time()
     7         print('the func run time is %s'%(stop_time-start_time))
     8     return deco
     9 @timmer
    10 def test1():
    11     time.sleep(1)
    12     print('in the test1')
    13 @timmer
    14 def test2(name,age) :
    15     time.sleep(2)
    16     print('in the test2:',name,age)
    17 test1()
    18 test2('Alex',18)
    复制代码

    运行结果:

    in the test1
    the func run time is 1.0000572204589844
    in the test2: Alex 18
    the func run time is 2.0001144409179688

    二、生成器

          列表在使用前数据就已经生成了,但是我们往往只使用其中一部分数据,大部分数据用不到浪费空间。生成器generator只有在调用时才生成相应的数据。

          1. 列表生成式:如果要生成列表[1x1, 2x2, 3x3, ..., 10x10]怎么做?除了循环还可以用一行语句代替循环生成

    1 list=[x*x for x in range(1,11)]
    2 print(list)

    运行结果:

    [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

    这种写法就是Python的列表生成式,写列表生成式时,把要生成的元素 x * x 放到前面,后面跟 for 循环,就可以把list创建出来。

           2. 生成器:要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator

    1 g=(x*x for x in range(1,11))
    2 print(g)

    运行结果:

    <generator object <genexpr> at 0x005B37E0>

    创建listgenerator的区别仅在于最外层的[]()。list的元素我们可以一个个打印出,如果要打印generator中的元素需要借助next方法

    1 g=(x*x for x in range(1,11))
    2 print(next(g))
    3 print(next(g))
    4 print(next(g))

    运行结果:

    1
    4
    9

    但是generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。可以通过for循环来迭代它,并且不需要关心StopIteration的错误。

    1 g=(x*x for x in range(1,11))
    2 for i in g:
    3     print(i)

    运行结果:

    复制代码
     1 1
     2 4
     3 9
     4 16
     5 25
     6 36
     7 49
     8 64
     9 81
    10 100
    复制代码

        3. 用函数生成generator:generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。例如,斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

    复制代码
    1 def fib(max):
    2     n,a,b=0,0,1
    3     while n<max:
    4         print(b)
    5         a,b=b,a+b
    6         n=n+1
    7     return 'done'
    8 f=fib(6)
    复制代码

    运行结果:

    复制代码
    1 1
    2 1
    3 2
    4 3
    5 5
    6 8
    复制代码

    上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

    复制代码
     1 def fib(max):
     2     n,a,b=0,0,1
     3     while n<max:
     4         yield b
     5         a,b=b,a+b
     6         n=n+1
     7     return 'done'
     8 f=fib(6)
     9 
    10 while True:
    11     try:
    12         x = next(f)
    13         print('f:',x)
    14     except StopIteration as e:
    15         print('Generator return value:',e.value)
    16         break
    复制代码

    运行结果:

    复制代码
    f: 1
    f: 1
    f: 2
    f: 3
    f: 5
    f: 8
    Generator return value: done
    复制代码

     generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

  • 相关阅读:
    x264
    [转贴]使用dbstart 和dbshut 脚本来自动化启动和关闭数据库
    企业搜索引擎开发之连接器connector(二十六)
    企业搜索引擎开发之连接器connector(二十五)
    深入分析 Java 中的中文编码问题
    深入分析 Java I/O 的工作机制
    企业搜索引擎开发之连接器connector(二十四)
    企业搜索引擎开发之连接器connector(二十三)
    企业搜索引擎开发之连接器connector(二十二)
    企业搜索引擎开发之连接器connector(二十一)
  • 原文地址:https://www.cnblogs.com/mrdz/p/5972158.html
Copyright © 2011-2022 走看看