python迭代器和生成器

(13) 第13章:迭代器和生成器

迭代器或者生成器不会提前去申请内存,等用的时候才会产生内存,所以只是提供了产生元素的方法
1、range函数

py3—>range返回是range对象,py2—>range返回的是list
若list是个很大的数据的情况下,py3不会直接返回一个大数据的list(占内存),只是一个对象
range的三个参数:起始数据、结束数据(不包含)、步进(两个数据的间隔)
如range(-4) —>[],只有一个参数的情况下是结束数据
range的方向看第三个参数的正负,正:左往右,负:右往左

2、可迭代,迭代器
from collections import Iterable,Iterator

可迭代对象:实现了迭代器协议的对象,在产生的类中定义了__iter__()方法
Iterable:可迭代对象 判断是否是可迭代对象 if isinstance(a,Iterable)
Iterator:迭代器 判断是否是迭代器 if isinstance(a,Iterator)
字符串、列表、元组、字典都是可迭代对象
特性:迭代器只能迭代一次,迭代完里面的元素就没了,list或者其他容器,如果元素很多的情况下,是直接申请内容空间把元素放到内存里面,会消耗大量内存,而迭代器是生成一个迭代器对象,在用到元素的时候才会去申请内容空间放置这个元素
iter(a):将
可迭代对象a
转换成迭代器,用到元素的时候才生成元素,不会消耗大量内存
可迭代对象不是迭代器,构造的迭代器—>参数数一个可迭代对象
自定义可迭代对象:

class MyIter():
	def __init__(self,num):
		self.num = num
	def __iter__(self):
		return iter(self.num.split(' '))
a_tier = MyIter('a b c d e f g')
for i in a_tier:
	print(i)

**总结:**迭代器是可迭代对象,可迭代对象不一定是迭代器
**迭代器优点:**不依赖与索引,迭代器对于内存的优化,同一时间只产生一个数据,而list同一时间是全部的元素数据
**迭代器缺点:**只能往后取值,而且是一次性的,每个元素只能迭代一次,不能统计迭代器的元素个数和迭代器长度
**取出迭代器的元素next():print(next(迭代器名)) 多次迭代则多次调用next()取元素,若next()的时候超出了迭代器的元素个数的限制会报错(StopIteration)
还可以通过for循环取出迭代器元素
**迭代器:**能被next(xxx对象)方法调用,有__iter__()__next__()方法
__iter__():返回迭代器本身
__next__():返回下一个元素,定义了这个方法后就能通过next()获取元素
next():函数里面有定义__next__就能通过这个方法获取元素,又或者可以说定义了__next__的对象就是一个迭代器
自定义迭代器:主要是实现__next__,和__iter__方法

# 自定义一个迭代器,实现类似与range函数的功能,产生 start 到end之间的数,两边闭合。
class MyRangeItertor:
    def __init__(self,start,end,step=1):
        self.start = start
        self.end =end
        self.step =step
    def __iter__(self):
        return self #返回迭代器本身
    def __next__(self):
        if self.start <= self.end:
            num = self.start
            self.start +=self.step
            return num
        else:
            raise StopIteration
a = MyRangeItertor(1,3)
for i in a:
    print(i)

dict.items():返回字典所有的数据项,按照数据原本的数据类型返回
enumerate():返回可迭代对象的索引和元素,如:for i in enumerate([1,2,3]):print(i)

3、推导式

列表推导式[][x for i in range(5)]—>返回list
[x for i in range(5) if x > 2]
字典推导式{}{key:value for key,value in enumerate(range(10))}
集合推导式{}{key for key in range(10) if key%2==0}

4、生成器
from collections import Generator
isinstance(a,Generator):判断是否是生成器
生成器(generator):python有一种“一边遍历一遍计算值”的方式产生可迭代对象,这就是生成器。生成器是一种特殊的迭代器,返回结果用yield关键字在运行时产生,前期不占内存,解决列表推导式占额外内存的问题。可以通过send()函数给生成器发信号

构造生成器的方式一:生成器表达式,如下
b_gen = (x for x in range(10)):生成器表达式,不是元组,没有元组推导式,生成器也是一种迭代器,生成器的元素只能被遍历一次,拿了就没了
可通过next()一个一个取(超出限制的异常不会内部处理),可通过for循环取(自动处理异常)
close():生成器的方法,生成器对象执行这个方法后,就不能获取元素了,相当于没元素了,在用next(),则会报错StopIteration
send(a):可将a传递给yield表达式,然后赋值给一个变量,可以通过将这个变量作为某种命令,改变生成器的执行方式,停止或者改变
构造生成器的方式二:yield关键字+函数定义生成器

def fun(num):
	while num>2:
	#造成的现象是:取一个元素,代码会暂停,把元素for循环出来在执行下面代码
	yield num 
	#相当于把num抛出到函数外,函数代码暂停,保留上次执行的状态
	#把抛出的num传递给获取值的对象
	num -=1
#然后在通过for循环取生成器的元素:
for i in fun(6):
	print(i)

#生成器的斐波那契数列
def fib():
	start,end = 0,1
	while True:
		yield end
		start,end = end,end+start
from itertools import islice
#从一个迭代器里面获取其中的 x-xx项 组成一个有限序迭代器对象
print(list(islice(fib, 0, 10)))

send():生成器的方法,可传递一个参数给yield的变量,相当于给生成器传递一个指令
说明yield之后,下次执行是在yield这里开始执行,只是不会再返回

def fun_C():
	a = 1,step = 1
	while True:
		r = yield a
		if isinstance(r,int):
			step = r
		a+=step
f = fnu_c()
next(f)#打印f
next(f)#打印 None 和 2  None是r的值,则表明再次执行时从yield开始的
#f.send(None)#如send(),第一次要一定传None 相当于next(f)
f.send(100)#将100赋值给了 yield a  然后赋值给了r
next(f)#打印f 就变成了102

5、切片

a_list[a,b,c]:a切片的起始位置,b是结束位置(不包含),c是步长(正数方向是左往右,负数是右往左)

6、从itertools中导入一些常用迭代器。
count为寄数器, count(start=1,step=3), 没有上限

from itertools import count
#产生一个无限的迭代器,去3开始步长为2的数,可以无限取
counter = count(3,2)
next(counter)
next(counter)
next(counter)
from itertools import islice
#获取一个无限的迭代器的90-100的10个组成的有限序列
print(list(islice(counter , 90, 100)))

islice从一个无限序列中提取出一个有限序列。
islice(obj, start,stop,step)
举例:斐波拉契数列重新实现

class Fib:
    def __init__(self):
        self.left = 0
        self.current = 1
    def __iter__(self):
        return self
    def __next__(self):
        value = self.current
        self.left, self.current = self.current, self.current + self.left
        return value
# 获取斐波拉契数列迭代器的前10个元素。
from itertools import islice
f = Fib()
#从一个迭代器里面获取其中的 x-xx项 组成一个有限序迭代器对象
print(list(islice(f, 0, 10)))

cycle将一个有限序列变为一个无限序列。

week_days = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六']
cycle_week = cycle(week_days)
for i in range(10):
    print(next(cycle_week))

dis:**方法可以直接看一段代码的执行过程

import dis
#看字符串里面的代码执行的过程
dis.dis('for i in range(10):print(i)')

你可能感兴趣的:(python,python基础)