Python生成器、装饰器

## 生成器
  - 生成器是用来创建Python序列的一个对象
  - 通常生成器是为迭代器产生数据的
  - 例如range()函数就是一个生成器
  - 每次迭代生成器时,它都会记录上一次调用的位置,并返回下一个值,这使程序不需要创建和存储完整的序列

## 生成器函数
  - 生成器函数与普通函数类似,但它的返回值使用yield语句,而不是return

 1 def my_range(start=0, last=10, step=1):
 2     number = start
 3     while number < last:
 4         yield number
 5         number += step
 6     
 7 my_range     # 是一个普通函数
 8 # <function my_range at 0x7efe3dbf2e18>
 9 
10 my_range()   # 返回一个生成器对象
11 # <generator object my_range at 0x7efe3daac360>
12 
13 list(my_range(1, 10))
14 # [1, 2, 3, 4, 5, 6, 7, 8, 9]          

## 装饰器

  - 装饰器的作用在于在不改变原有代码结构的前提下,对原有代码的功能进行补充扩展
  - 装饰器的本质上是接受函数为参数的高阶函数,它把一个函数作为参数输入并且返回一个功能拓展后的新函数

 1 # 装饰器函数,为函数添加两条语句
 2 def deco(fn):
 3     def new_func(*args):  # 内部函数的参数需要与传入的fn的参数相同
 4         print("执行函数:{0}".format(fn.__name__))
 5         result = fn(*args)
 6         print("函数执行结果:{0}".format(result))
 7         return result
 8     return new_func
 9 
10 
11 @deco    # 使用@装饰函数名,使用装饰器之后,add实际上已经指向了doco函数返回的新函数
12 def add(*args):
13     print("我是核心代码,可不能改动我")
14     result = 0
15     for n in args:
16         result += n
17     return result
18 
19 
20 add(1, 2, 3, 4)
21 """
22 执行结果:
23     执行函数:add
24     我是核心代码,可不能改动我
25     函数执行结果:10
26 """

    

    - 一个函数可以有多个装饰器

    - 最靠近函数的装饰器会先执行,然后一次向上执行装饰器

 1 def count_param(fn):
 2     def new_func(*args):
 3         amount = len(args)
 4         fn(*args)
 5         print("参数个数为:{0}".format(amount))
 6         return amount
 7     return new_func
 8 
 9 
10 @count_param
11 @deco
12 def add(*args):
13     print("我是核心代码,可不能改动我")
14     result = 0
15     for n in args:
16         result += n
17     return result
18 
19 
20 add(1, 2, 3, 4)
21 """
22 执行结果:
23     执行函数:add
24     我是核心代码,可不能改动我
25     函数执行结果:10
26     参数个数为:4
27 """

    - 如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数

 1 import time
 2 
 3 
 4 def log(now_time):
 5     def deco(fn):
 6         def new_func(*args, **kwargs):
 7             print(now_time)
 8             return fn(*args, **kwargs)
 9         return new_func
10     return deco
11 
12 
13 @log(time.asctime(time.localtime(time.time())))
14 def add(*args):
15     print("我是核心代码,可不能改动我")
16     result = 0
17     for n in args:
18         result += n
19     return result
20 
21 
22 add(1, 2, 3, 4)
23 """
24 执行结果:
25     函数开始时间:Sun Jul  1 15:30:14 2018
26     我是核心代码,可不能改动我
27 """

  - 此时打印add函数的__name__属性发现:

print("核心函数名:{0}".format(add.__name__))
"""
输出:
    核心函数名:new_func
"""

  

  - 这表明虽然装饰器表面上并没有改变核心函数的内容,但实际上还是对核心函数的属性进行了修改,所以还需要将核心函数的__name__属性复制到新函数

 1 import time
 2 
 3 
 4 def log(now_time):
 5     def deco(fn):
 6         def new_func(*args, **kwargs):
 7             # 将原函数的__name__属性复制到新函数
 8             new_func.__name__ = fn.__name__
 9             print(now_time)
10             return fn(*args, **kwargs)
11         return new_func
12     return deco
13 
14 
15 @log(time.asctime(time.localtime(time.time())))
16 def add(*args):
17     print("我是核心代码,可不能改动我")
18     result = 0
19     for n in args:
20         result += n
21     return result
22 
23 
24 add(1, 2, 3, 4)
25 print("核心函数名:{0}".format(add.__name__))
26 """
27 执行结果:
28     Sun Jul  1 15:43:00 2018
29     我是核心代码,可不能改动我
30     核心函数名:add
31 """    

  - 在functools里面有一个专门的函数处理这个问题

 1 import time
 2 import functools
 3 
 4 
 5 def log(now_time):
 6     def deco(fn):
 7         @functools.wraps(fn)      # 在新的函数上添加装饰器,修改新函数的__name__属性
 8         def new_func(*args, **kwargs):
 9             print(now_time)
10             return fn(*args, **kwargs)
11         return new_func
12     return deco
13 
14 
15 @log(time.asctime(time.localtime(time.time())))
16 def add(*args):
17     print("我是核心代码,可不能改动我")
18     result = 0
19     for n in args:
20         result += n
21     return result
22 
23 
24 add(1, 2, 3, 4)
25 print("核心函数名:{0}".format(add.__name__))
26 ”“”
27 执行结果:
28     Sun Jul  1 15:48:10 2018
29     我是核心代码,可不能改动我
30     核心函数名:add
31 “”“

本文参考:

  [美]Bill Lubanovic 《Python语言及其应用》
  https://www.liaoxuefeng.com 廖雪峰的官方网站 

猜你喜欢

转载自www.cnblogs.com/hycstar/p/9250403.html