可迭代对象:
for循环后面必须添加可迭代对象

s1 = '123' for i in s1: print(i) for i in 123: print(i) #报错,数字是不可迭代对象。'int' object is not iterable
内部含有__iter__方法的就是可迭代对象,遵循可迭代协议。
dir(判断内部都有什么方法)

print(dir('123')) #'__inter__' #打印出:'__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', .....'
判断是不是可迭代对象:

print('__iter__'in dir([1,2,3])) print('__iter__'in dir({'name':'alex'})) print('__iter__'in dir({'name'})) print('__iter__'in dir((1,2,3))) print('__iter__'in dir(1)) #Flase print('__iter__'in dir(True)) #Flase print('__iter__'in dir(range(10)) ) with open('log1',encoding='utf-8')as f1: print('__iter__'in dir(f1))#(文件句柄)
文件句柄是迭代器,其他的是可迭代对象(元组,列表,字典,range)
迭代器:
(什么是迭代器?)
可迭代对象通过.__iter__()可以转换成迭代器,满足迭代器协议。
内部有__iter__且__next__方法的就是迭代器。
l = [1,2,3]
l_obj = l.__iter__()
print(l_obj)
迭代器的取值有两种方法:
第一种:__netx__(一个next打印一个值,不可逆)

l = [1,2,3] l_obj = l.__iter__() print(l_obj.__next__()) #1 print(l_obj.__next__())#2
第二种:for 循环
for循环怎么回事,要求必须是可迭代对象
for循环的内部,使用的就是迭代器
最开始,获取迭代器,然后每次执行的时候,都是__next__()

l = [1,2,3] l_obj = l.__iter__() for i in l_obj: print(i)
判断迭代器方法:
方法一:判断__iter__和__next__在不在dir(对象中)(很low)

l = [1,2,3] l_obj = l.__iter__() print('__next__'in dir(l_obj))
方法二:(导入模块)

from collections import Iterable#(迭代对象) from collections import Iterator#(迭代器) print(isinstance('123',Iterable)) print(isinstance('123',Iterator))
实际上可迭代对象是不可以一个一个的一次取值的,因为他没有__next__方法。
for 循环提供一个机制:
1,将可迭代对象转化成迭代器。
2,利用__next__进行取值。
3,用try异常处理方法防止报错。
面试题:处理异常 例题1

l = [1,2,3,4,5] l_obj = l.__iter__() while True: print(l_obj.__next__()) 报错StopIteration 打印出1,2,3,4,5 例题2 l = [1,2,3,4,5] l_obj = l.__iter__() while True: try: print(l_obj.__next__()) except StopIteration: pass 例题三: l = [1,2,3,4,5] l_obj = l.__iter__() while True: try: print(l_obj.__next__()) except StopIteration: break 例题四: l = [1,2,3,4,5] l_obj = l.__iter__() while True: try: print(l_obj.__next__()) except Exception: break try Exception(万能错误):处理万能错误报错
面试题:用while循环实现for循环的功能

l = [1,2,3,4,5] l_obj = l.__iter__() while True: try: print(l_obj.__next__()) except Exception: break #######try Exception(万能错误):处理万能错误报错
为什么要有for循环?
序列类型字符串,列表,元组都有下标,你用上述的方式访问,perfect!但是你可曾想过非序列类型像字
典,集合,文件对象的感受,所以嘛,年轻人,for循环就是基于迭代器协议提供了一个统一的可以遍历所有
对象的方法,即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去
实现循环访问,这样所有的对象就都可以通过for循环来遍历了,而且你看到的效果也确实如此,这就是无所
不能的for循环,最重要的一点,转化成迭代器,在循环时,同一时刻在内存中只出现一条数据,极大限度
的节省了内存~
迭代器的作用:
1,节省内存。
2,满足惰性机制。
3,取值过程不可逆(一条路走到黑)。
生成器:
生成器本质也是迭代器,生成器是自己用python写的迭代器。
1,通过生成器函数构建。
2,通过生成器推导式构建。
3,通过数据的转换也可以获取到生成器

例题1, def func1(): print(666) return 222 ret = func1() print(ret) # 666 222 例题2, def func1(): print(666) yield 222 g_obj = func1() #生成器迭代对象generator object print(g_obj) 例题3 def func1(): print(666) yield 222 g_obj = func1() print(g_obj.__next__())
有yield就是生成器 ,一个yield对应一个next:

def func1(): print(111) print(333) yield 222 print(666) yield 777 g_obj = func1() print(g_obj.__next__()) print(g_obj.__next__())
例题1:做衣服10000套

def cloth1(): for i in range(1,10001): print('衣服%s'%i) cloth1() 2, def cloth2(): for i in range(1,10001): yield '衣服%s'%i g = cloth2() print(g.__next__()) print(g.__next__()) print(g.__next__()) 3. def cloth2(): for i in range(1,10001): yield '衣服%s'%i g = cloth2() for i in range(1,51): print(g.__next__())
yield可以一段一段循环打印,for i in range全部循环打印

def func1(): print(111) #111 print(333) #333 yield 222 #222 print(666) #666 yield 777 #777 yield 888 g_obj = func1() print(g_obj.__next__()) print(g_obj.send(2))
send:
1,send 具有next功能(一个send对应一个next)
2,send可以给上一个yield传值。
3,第一个取值不能使用send
4,最后一个yield不会得到send的值。
传值例子:

def func1(): count = yield 222 print(count) yield 777 yield 888 g_obj = func1() #222 2 777 print(g_obj.__next__()) print(g_obj.send(2))
send取值不能是第一个例子(会报错)

def func1(): count = yield 222 print(count) yield 777 yield 888 g_obj = func1() print(g_obj.send(555)) print(g_obj.send('wusir'))
yield 和 return 区别 1,如果函数中包含了yeild,这个函数是一个生成器函数,执行函数的时候是:生成器 2,生成器执行__next__(),执行到下一个yield 3,yeild的作用和return基本相同,但是只负责返回,不会结束函数 4,return 结束函数
列表推导式:
列表推导式:能用列表推到式完成的,用python代码都可以完成。
用一句话构建一个你想要的列表。
优点:简单,稍微难理解
缺点:不能用debug
创建列表1~11:
li = []
for i in range(1,12):
li.append(i)
print(i)
列表推导式方法:
li = [i for i in range(1,12)]
#[变量(加工后的变量)for 变量 in 可迭代对象] 遍历模式
print(li)
2,
li = []
for i in range(1,12):
li.append('python%s期'%i)
print(li)
li = ['python%s期'% i for i in range(1,12)]
print(li)
[变量(加工后的变量)for 变量 in 可迭代对象] 筛选模式
1,筛选,100以内所有的奇数。

l2 = [i for i in range(1,101) if i % 2 == 1] l2 = [i for i in range(1,101,2)] print(l2)
2,10以内所有书的平方。

l2 = [i*i for i in range(1,11)] print(l2)
3,将100以内所有能被3整除的数留到列表中。

l2 = [i for i in range(1,101) if i % 3 == 0] print(l2)
生成器表达式:
g = (i*i for i in range(1,11))
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
for i in g:
print(i)
列表推导式 简单明了,但是占内存
生成器表达式 节省内存,不易看出。
1,把列表解析式的[]换成()得到的就是生成器表达式。
2,列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存。
3,python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访
问对象的。例如,sum函数是python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了
迭代器协议,所以,我们可以直接这样计算一系列值得和。
4,30以内所有能被3整除的数的平方。

li = [i*i for i in range(1,31)if i % 3 == 0] print(li)
5,找出名字带有两个e的名字

names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] l3 = [name for i in names for name in i if name.count('e') == 2] print(l3)
6,字典键值翻转:

mcase = {'a':10,'b':34} mcase_frequency = {mcase[k]:k for k in mcase} print(mcase_frequency)