装饰器,迭代器,生成器
1. 装饰器
定义: 在函数运行前或运行后可以添加额外功能且不影响该函数原有的代码功能,并且还可以进行函数执行后的清理工作。
语法
语法:
@func1
def func2():
pass
装饰器做得事情就是func1(func2)我们传递了一个函数对象到我们的装饰器里面然后先执行装饰器func1其中的内容,然后再执行函数func2
三类装饰器
1.普通无参装饰器
def wai(func): # func 被装饰函数
def nei(): # a,b 表明被装饰函数的参数
print('函数执行前添加')
res = func()
print('函数执行后添加')
return res # 内层函数将外层函数调用的被装饰函数作为参数返回
return nei # 外层函数返回内层函数的函数名
@wai
def func():
print("这是一个函数")
return 1
func()
2.被装饰函数带参数
def wai(func): # func 被装饰函数
def nei(a,b): # a,b 表明被装饰函数的参数
a = a + 1
b = b + 1
print('函数执行前添加')
res = func(a,b)
print('函数执行后添加')
return res # 内层函数将外层函数调用的被装饰函数作为参数返回
return nei # 外层函数返回内层函数的函数名
@wai
def func(a,b):
print("这是一个函数")
return a+b
res = func(1,2)
print(res)
3.装饰器函数有参数
def f(is_ok): # 在装饰器函数设置参数如果条件成立执行
def wai(func): # func 被装饰函数
def nei(a,b): # a,b 表明被装饰函数的参数
if is_ok:
a = a + 1
b = b + 1
print('函数执行前添加')
res = func(a,b)
print('函数执行后添加')
return res # 内层函数将外层函数调用的被装饰函数作为参数返回
else:
return func(a,b)
return nei # 外层函数返回内层函数的函数名
return wai
@f(is_ok=0)
def func(a,b):
print("这是一个函数")
return a+b
res = func(1,2)
print(res)
2. 生成器
生成器能够让出控制权并在适合的时间恢复到原来的位置继续运行,其根本原因是 生成器是一种特殊的迭代器,而迭代器有一个特点就是 能够记住当前的迭代位置。
具有特殊功能的迭代器:当控制流转换到迭代器上时,迭代器负责生成和返回下一个元素。一旦下一个元素准备就绪,迭代器就让出控制流。
yield关键字:让出控制权并生成迭代器的返回值。
生成器能够让出控制权
普通的迭代器不能让出控制权
有了生成器(记住位置、恢复位置),就能在用户态切换两个函数的执行(这个就叫协程)
所以生成器可以实现协程,这有个进化的过程——
- yield 实现协程
- yield态繁琐,就有人封装各种库,就了 greenlet , 就有了gevent
- 官方发现实现协程的方法五花八门,官方为了统一协程的实现,在新版本的Python中添加
了一个官方库 asyncio 库
- 官方为了简化asyncio的使用,添加 async / await 两个关键字
定义: 生成器是特殊的迭代器,生成器自动实现了迭代器协议(iter,next), 不需要手动维护这两种方法。
元组推导式
ge = (var for var in range(10))
调用生成器的两种方式(next(ge), ge.__next__(),在生成器next()下一个值时,到最后一个就会报出异常(StopIteration))
该表达式可以在处理大量数据保存在序列时,比较费内存,而当前的生成器方式可以延迟生产数据,节约内存。而数据只有在需要的生产。
[生成器的好处,在需要它的时候再进行next()取出,比较节省内存,再python2中都在列表中占用内存比较大]
**生成器--函数实现生成器 **
重点:如果在函数中出现了yield关键字,该函数将不在是普通函数,而是生成器函数。
return:函数中起到 返回并且终止函数
yield: 函数中起到 返回并且挂起函数
def gen():
# return: 返回并且终止函数
# yield: 返回并且挂起函数
# next: 下一个(唤醒)--> yield return
for i in range(10):
yield i
a = gen()
res = next(a)
print(a)
print(res)
res = next(a)
print(res)
生成器创建后有三个方法
- 1.close() 在指定的位置可以手动关闭生成器函数,会使后面的生成器使用直接返回Stoplteration 异常
def gen():
# return: 返回并且终止函数的作用
# yield: 返回并且挂起函数的作用
# next: 下一个(唤醒)--> yield return
for i in range(10):
yield i
a = gen()
res = next(a)
print(a)
print(res)
res = next(a)
print(res)
a.send(11)
# a.close() # 关闭生成器 关闭后相当于抛出StopIteration异常
- 2.send() 生成器函数可以接受一个外部传入的变量,并且可以像函数处理参数一样将这个变量在运行期间进行处理并返回;在使用send函数时,
第一次首先需要传入None或next函数调用的形式将生成器第一个值生产。
def gen():
num = 0
while True:
var = yield num # 将num赋给var,a.send() 传进来的值在这里
yield num
num += var
a = gen()
res = next(a)
print(a)
print(res)
a.send(10) # 向函数传递参数值
res = next(a)
print(res)
- 3.throw() 用来像生成器函数传入一个异常,使生成器结束,可以自己定义其位置。
def gen():
num = 0
while True:
var = yield num # 将num赋给var,a.send() 传进来的值在这里
yield num
num += var
a = gen()
res = next(a)
print(a)
print(res)
a.send(10) # 向函数传递参数值
res = next(a)
print(res)
a.send(11)
a.throw(ValueError) # 可以自定义抛出异常,抛出异常的类型
res = next(a)
print(res)
3.迭代器
迭代器与Python2.2版本后添加,他为类序列对象提供了一个可以使其进化为迭代器的接口 iter
迭代器对象内部会维持一个状态,用于记录当前迭代的状态,以方便下次迭代时提取正确的数据元素
可迭代对象内置__iter__函数,该函数将对象处理为可迭代对象
任何实现__iter__和__next__的对象都可看作迭代器
__iter__返回迭代器自身、__next__返回迭代的下个值
迭代器没有返回的元素,抛出StopIteration
迭代器核心:迭代器自身需要记住当前的迭代位置,迭代器自身需要知道何时迭代完毕
什么是可迭代对象?像list,tuple,set等可以遍历的对象都是可迭代对象,生成器也是可迭代对象
什么是迭代器? 迭代器是一种设计模式,是抽象出的一种独立于数据结构的东西,迭代器专门负责可迭代对象所有元素的顺序访问,迭代器知道当前迭代的位置,并知道何时迭代完毕
可以直接利用的迭代器
无限迭代器生产:
无限迭代器
from itertools import count
有限数据对象晋升为无限迭代器
from itertools import cycle
有限迭代器生产:
iter()
from itertools import islice
islice(iterable, stop)
islice(iterable, start, stop[, step])
自定义迭代器
自定义迭代器:__iter__()、__next__()
自定义迭代器实现斐波那契
# 迭代器实现斐波那契
class Func():
def __init__(self):
self.prev = 0
self.curr = 1
def __iter__(self):
return self
def __next__(self):
value = self.curr
self.curr += self.prev # 当前值 等于上一次的当前值 加上一次的上一次的值
self.prev = value
return value
if __name__ == '__main__':
f = Func()
print(next(f))
print(next(f))
总结
使用迭代器不要求事先准备好整个迭代过程中的所有元素。
迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后元素可以不存在或者被销毁。
因此迭代器只能往前,不能后退适合遍历一些数量巨大甚至无限的序列。