## 生成器
- 生成器是用来创建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语言及其应用》