迭代器 生成器 推导式

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

s1 = '123'
for i in s1:
    print(i)

for i in 123:
    print(i)  #报错,数字是不可迭代对象。'int' object is not iterable
View Code

内部含有__iter__方法的就是可迭代对象,遵循可迭代协议。
dir(判断内部都有什么方法)

 

print(dir('123'))       #'__inter__'
#打印出:'__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', .....'
View Code

 

判断是不是可迭代对象:

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))#(文件句柄)
View Code

文件句柄是迭代器,其他的是可迭代对象(元组,列表,字典,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
View Code

第二种:for 循环

for循环怎么回事,要求必须是可迭代对象
for循环的内部,使用的就是迭代器
最开始,获取迭代器,然后每次执行的时候,都是__next__()

l = [1,2,3]
l_obj = l.__iter__()
for i in l_obj:
    print(i)
View Code

判断迭代器方法:
方法一:判断__iter__和__next__在不在dir(对象中)(很low)

l = [1,2,3]
l_obj = l.__iter__()
print('__next__'in dir(l_obj))
View Code

方法二:(导入模块)

from collections import Iterable#(迭代对象)
from collections import Iterator#(迭代器)
print(isinstance('123',Iterable))
print(isinstance('123',Iterator))
View Code

实际上可迭代对象是不可以一个一个的一次取值的,因为他没有__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(万能错误):处理万能错误报错
View Code

面试题:用while循环实现for循环的功能

l = [1,2,3,4,5]
l_obj = l.__iter__()
while True:
    try:
        print(l_obj.__next__())
    except Exception:
        break
#######try     Exception(万能错误):处理万能错误报错
View Code

为什么要有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__())
View Code
有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__())
View Code
例题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__())
View Code

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))
View Code

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))
View Code

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'))
View Code
yieldreturn 区别
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)
View Code

2,10以内所有书的平方。

l2 = [i*i for i in range(1,11)]
print(l2)
View Code

3,将100以内所有能被3整除的数留到列表中。

l2 = [i for i in range(1,101) if i % 3 == 0]
print(l2)
View Code

生成器表达式:
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)
View Code

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)
View Code

6,字典键值翻转:

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

 

posted on 2018-06-19 12:47  liangliang123456  阅读(163)  评论(0编辑  收藏  举报

导航