## 生成器
- 生成器是用来创建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 “”“
- 类装饰器
1 class Test(object): 2 def __init__(self, fn): 3 self.fn = fn 4 5 # 重写__call__函数,使实例能够像函数一样调用 6 def __call__(self, *args, **kwargs): 7 print("这是基于类的修饰") 8 return self.fn(*args, **kwargs) 9 10 11 @Test 12 def core_func(a, b): 13 return a + b 14 15 16 print(core_func(2, 3)) 17 """ 18 输出: 19 这是基于类的修饰 20 5 21 """
- 类装饰器带参数
1 import datetime 2 import functools 3 4 5 class Test(object): 6 def __init__(self, log): 7 self.log = log 8 9 # 重写__call__函数,使实例能够向函数一样调用 10 def __call__(self, fn): 11 @functools.wraps(fn) # 同样在这里使用functools.wraps(),将原函数__name__属性复制到新函数 12 def wrapper(*args, **kwargs): 13 print(self.log) 14 print("执行函数:%s" % fn.__name__) 15 return fn(*args, **kwargs) 16 return wrapper 17 18 19 @Test(datetime.datetime.now()) 20 def core_func(a, b): 21 return a + b 22 23 24 @Test(datetime.datetime.now()) 25 def say_hi(): 26 print("Hi") 27 28 29 print(core_func(2, 3)) 30 print(core_func.__name__) # 输出:core_func 31 say_hi() 32 print(say_hi.__name__) # 输出:say_hi 33 """ 34 输出: 35 2018-07-02 10:55:27.258637 36 执行函数:core_func 37 5 38 core_func 39 2018-07-02 10:55:27.258696 40 执行函数:say_hi 41 Hi 42 say_hi 43 """
本文参考:
[美]Bill Lubanovic 《Python语言及其应用》
https://www.liaoxuefeng.com 廖雪峰的官方网站