python 迭代器 生成器
迭代器 与 生成器
"""
什么是迭代器
迭代:更新换代(重复)的过程,每次的迭代都必须基于上一次的结果
迭代器:迭代取值的工具
为什么要用
迭代器给你提供了一种不依赖于索引取值的方式
如何用
"""
不算 因为只是简单的重复
n = 0
while True:
print(n)
重复 + 每次迭代都是基于上一次的结果而来的
l = [1,2,3,4]
s = 'hello'
n = 0
while n < len(s):
print(s[n])
n += 1
"""
需要迭代取值的数据类型
字符串
列表
元组
字典
集合
"""
可迭代对象
只有内置有__iter__方法的都叫做可迭代对象
"""
补充:针对双下线开头双下划线结尾的方法
推荐读:双下+方法名
基本数据类型中
是可迭代对象的有
str list tuple dict set
文件对象(执行内置的__iter__之后还是本身 没有任何变化):文件对象本身就是迭代器对象
"""
n = 1
f = 1.1
s = 'hello'
l = [1,2,34,]
t = (1,2,34)
s1 = {1,2,3,4}
d = {'name':'jason'}
f1 = open('xxx.txt','w',encoding='utf-8')
res = s.__iter__() res = iter(s)
print(s.__len__()) 简化成了len(s)
res1 = l.__iter__() res1 = iter(l)
res2 = f1.__iter__() res2 = iter(f1)
print(res,res1,res2)
print(f1)
可迭代对象执行内置的__iter__方法得到就是该对象的迭代器对象
"""
迭代器对象
1.内置有__iter__方法
2.内置有__next__方法
ps:迭代器一定是可迭代对象
而可迭代对象不一定是迭代器对象
"""
l = [1,2,3,4]
生成一个迭代器对象
iter_l = l.__iter__()
迭代器取值 调用__next__
print(iter_l.__next__())
print(iter_l.__next__())
print(iter_l.__next__())
print(iter_l.__next__())
print(iter_l.__next__()) 如果取完了 直接报错
d = {'name':'jason','password':'123','hobby':'泡m'}
将可迭代对象d转换成迭代器对象
iter_d = d.__iter__()
迭代器对象的取值 必须用__next__
print(iter_d.__next__())
print(iter_d.__next__())
print(iter_d.__next__())
print(iter_d.__next__()) 取完了 报错StopIteration
f1 = open('xxx.txt','r',encoding='utf-8')
调用f1内置的__iter__方法
iter_f = f1.__iter__()
print(iter_f is f1)
"""
迭代器对象无论执行多少次__iter__方法得到的还是迭代器对象本身(******)
"""
print(f1 is f1.__iter__().__iter__().__iter__().__iter__())
"""
问:__iter__方法就是用来帮我们生成迭代器对象
而文件对象本身就是迭代器对象,为什么还内置有__iter__方法???
"""
d = {'name':'jason','password':'123','hobby':'泡m'}
iter_d = d.__iter__()
print(d.__iter__().__next__())
print(d.__iter__().__next__())
print(d.__iter__().__next__())
print(iter_d.__next__())
print(iter_d.__next__())
print(iter_d.__next__())
print(iter_d.__next__())
异常处理
while True:
try:
print(iter_d.__next__())
except StopIteration:
print('老母猪生不动了')
break
f = open('xxx.txt','r',encoding='utf-8')
iter_f = f.__iter__()
print(iter_f.__next__())
print(iter_f.__next__())
print(iter_f.__next__())
"""
迭代器取值的特点
1.只能往后依次取 不能后退
"""
d = {'name':'jason','password':'123','hobby':'泡m'}
for i in d:
print(i)
for循环后面的in关键 跟的是一个可迭代对象
"""
for循环内部的本质
1.将in后面的对象调用__iter__转换成迭代器对象
2.调用__next__迭代取值
3.内部有异常捕获StopIteration,当__next__报这个错 自动结束循环
"""
for i in 1:
pass
iter(1)
"""
可迭代对象:内置有__iter__方法的
迭代器对象:既内置有__iter__也内置有__next__方法
迭代取值:
优点
1.不依赖于索引取值
2.内存中永远只占一份空间,不会导致内存溢出
缺点
1.不能够获取指定的元素
2.取完之后会报StopIteration错
"""
l = [1,2,3,4]
res = map(lambda x:x+1,l)
print(map(lambda x:x+1,l))
print(res.__next__())
print(res.__next__())
print(res.__next__())
l1 = [1,2,3,4,5]
l2 = ['a','b','c']
print(zip(l1,l2))
"""
生成器:用户自定义的迭代器,本质就是迭代器
"""
def func():
print('first')
yield 666 函数内如果有yield关键字,那么加括号执行函数的时候并不会触发函数体代码的运行
print('second')
yield 777
print('third')
yield 888
print('forth')
yield
yield
yield后面跟的值就是调用迭代器__next__方法你能得到的值
yield既可以返回一个值也可以返回多个值 并且多个值也是按照元组的形式返回
g = func() 生成器初始化:将函数变成迭代器
print(g)
print(g.__next__())
print(g.__next__())
print(range(1,10))
for i in range(1,10,2):
print(i)
def my_range(start,end,step=1):
while start < end:
yield start
start += step
for j in my_range(1,100,2):
print(j)
yield支持外界为其传参
def dog(name):
print('%s 准备开吃'%name)
while True:
food = yield
print('%s 吃了 %s'%(name,food))
def index():
pass
当函数内有yield关键字的时候,调用该函数不会执行函数体代码
而是将函数变成生成器
g = dog('egon')
g.__next__() 必须先将代码运行至yield 才能够为其传值
g.send('狗不理包子') 给yield左边的变量传参 触发了__next__方法
g.send('饺子')
"""
yield
1.帮你提供了一种自定义生成器方式
2.会帮你将函数的运行状态暂停住
3.可以返回值
与return之间异同点
相同点:都可以返回值,并且都可以返回多个
不同点:
yield可以返回多次值,而return只能返回一次函数立即结束
yield还可以接受外部传入的值
"""
列表生成式
res = [i for i in range(1,10) if i != 4]
print(res)
res = (i for i in range(1,100000000) if i != 4) 生成器表达式
print(res)
"""
生成器不会主动执行任何一行代码
必须通过__next__触发代码的运行
"""
print(res.__next__())
print(res.__next__())
print(res.__next__())
print(res.__next__())
一次全部读取整个文件占内存
f = open('xxx.txt','r',encoding='utf-8')
data = f.read()
print(len(data))
f.close()
with open('xxx.txt','r',encoding='utf-8') as f:
n = 0
for line in f:
n += len(line)
print(n)
g = (len(line) for line in f)
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(sum(g))
def add(n,i):
return n+i
def test():
for i in range(4):
yield i
g=test()
for n in [1,10]:
g=(add(n,i) for i in g)
第一次for循环g=(add(n,i) for i in test())
第二次for循环g=(add(n,i) for i in (add(n,i) for i in test()))
print(n)
res=list(g)
"""
for i in (add(10,i) for i in test()): 会执行所有的生成器内部的代码
add(n,i)
"""
A. res=[10,11,12,13]
B. res=[11,12,13,14]
C. res=[20,21,22,23] 答案
D. res=[21,22,23,24]
print(abs(-11.11)) 求绝对值
l = [0,1,0]
print(all(l)) 只要有一个为False就返回False
print(any(l)) 只要有一个位True就返回True
def index():
username = '我是局部名称空间里面的username'
print(locals()) 当前语句在哪个位置 就会返回哪个位置所存储的所有的名字
print(globals()) 无论在哪 查看的都是全局名称空间
index()
print(bin(10))
print(oct(10))
print(hex(10))
print(int('0b1010',2))
print(bool(1))
print(bool(0))
s = 'hello'
print(s.encode('utf-8'))
print(bytes(s,encoding='utf-8'))
可调用的(可以加括号执行相应功能的)
l = [1,2,3]
def index():
pass
print(callable(l))
print(callable(index))
print(chr(97)) 将数字转换成ascii码表对应的字符
print(ord('a')) 将字符按照ascii表转成对应的数
dir获取当前对象名称空间里面的名字
l = [1,2,3]
print(dir(l))
import test
print(dir(test))
print(test.name)
divmod 分页器
print(divmod(101,10))
total_num,more = divmod(900,11)
if more:
total_num += 1
print('总页数:',total_num)
enumerate 枚举
l = ['a','b']
for i,j in enumerate(l,1):
print(i,j)
eval exec
s = """
print('hello baby~')
x = 1
y = 2
print(x + y)
"""
eval(s)
exec(s)
eval不支持逻辑代码,只支持一些简单的python代码
s1 = """
print(1 + 2)
for i in range(10):
print(i)
"""
eval(s1)
exec(s1)
name = 'jason'
s2 = """
name
"""
print(eval(s2))
format 三种玩法
{}占位
{index} 索引
{name} 指名道姓
print(globals())
def login():
"""
一起嗨皮
:return:
"""
print(help(login))
isinstance 后面统一改方法判断对象是否属于某个数据类型
n = 1
print(type(n))
print(isinstance(n,list)) 判断对象是否属于某个数据类型
print(pow(2,3))
print(round(3.4))
"""
面向过程编程:就类似于设计一条流水线
好处:
将复杂的问题流程化 从而简单化
坏处:
可扩展性较差 一旦需要修改 整体都会受到影响
"""
迭代器示例
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration
myclass = MyNumbers()
myiter = iter(myclass)
for x in myiter:
print(x)
总结 :
迭代器 和生成器 其实都是一种类型,既都可以理解为 一个 按钮,你按一下 出一次结果,以此来达到节省内存的效果,注意的是 ,当 yeild被赋值时,需要考虑形参的传递,函数如果含有yeild 那么 函数名()并不会直接运行函数,而是生成器的初始化,然后我们可以 不断的用函数名__next__()的方法 获取yeild右边的返回值,随后yeild的左边的值会被传入下一次的函数运行中.

浙公网安备 33010602011771号