xingyemdd

导航

 

一、迭代器

如何从列表、字典中取值的:
1)index索引 ,key,前提必须知道索引或key值才能取到对应的value
2)for循环
凡是可以使用for循环取值的都是可迭代的
可迭代协议 :内部含有__iter__方法的都是可迭代的
迭代器协议 :内部含有__iter__方法和__next__方法的都是迭代器

 1 print(dir([1,2,3]))
 2 #>>>['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
 3 lst_iter = [1,2,3].__iter__()
 4 print(lst_iter.__next__())#>>>1
 5 print(lst_iter.__next__())#>>>2
 6 print(lst_iter.__next__())#>>>3
 7 
 8 #上面代码相当于for循环取值
 9 for i in [1,2,3]:   #  使用for循环时,在内部调用__iter__方法,变成迭代器。[1,2,3].__iter__()
10     print(i)
11 
12 #使用while循环实现for循环的机制
13 l = [1,2,3]
14 lst_iter = iter(l)   # iter(l)相当于l.__iter__(),都是产生一个迭代器
15 while True:
16     try:
17         print(next(lst_iter)) # next(lst_iter)相当于lst_iter.__next__()
18     except StopIteration:
19         break
20 
21 # 什么是可迭代的
22 # 什么是迭代器     迭代器 = iter(可迭代的),自带一个__next__方法
23 # 可迭代 最大的优势 节省内存
24 
25 #例:以下是python3运行的结果
26 from collections import Iterable,Iterator
27 print(range(100000000))
28 print(isinstance(range(100000000),Iterable))#判断是不是可迭代的
29 print(isinstance(range(100000000),Iterator))#判断是不是迭代器
30 # >>>range(0, 100000000)
31 # >>>True
32 # >>>False
33 
34 # python2 range 不管range多少 会生成一个列表 这个列表将用来存储所有的值
35 # python3 range 不管range多少 都不会实际的生成任何一个值
36 # 迭代器的优势:
37 #     节省内存
38 #     取一个值就能进行接下来的计算 ,而不需要等到所有的值都计算出来才开始接下来的运算 —— 快
39 # 迭代器的特性:惰性运算
40 
41 #
42 f = open()
43 for line in f:#用一行读一行
44 
45 # 可迭代对象:列表 字典 元组 字符串 集合 range 文件句柄 enumerate(加序号)

 二、生成器

生成器 Generator
自己写的迭代器 就是一个生成器
两种自己写生成器(迭代器)的机制:生成器函数   生成器表达式

1、生成器函数

 1 # 凡是带有yield的函数就是一个生成器函数
 2 def func():
 3     print('****')
 4     yield 1
 5     print('^^^^')
 6     yield 2   # 记录当前所在的位置,等待下一次next来触发函数的状态
 7 
 8 g = func()
 9 print('--',next(g))
10 #>>>****
11 #>>>-- 1
12 print('--',next(g))
13 #>>>^^^^
14 #>>>-- 2

例1:

# 需要定制200 0000件衣服
# 承包:牛翔  一起做完200 0000才进行反馈,这时候已经开到40期了
# 承包:赵英杰 200 0000,你每一期需要的时候才进行生产和反馈

def cloth(num):
    ret = []
    for i in range(num):
        ret.append('cloth%s'%i)
    return ret
ret=cloth(10)
print(ret)#>>>['cloth0', 'cloth1', 'cloth2', 'cloth3', 'cloth4', 'cloth5', 'cloth6', 'cloth7', 'cloth8', 'cloth9']

# 想要生成器函数执行,需要用next
def cloth_g(num):
    for i in range(num):
        yield 'cloth%s'%i

g = cloth_g(1000)
print(next(g))#>>>cloth0
print(next(g))#>>>cloth1
print(next(g))#>>>cloth2

例2:使用生成器监听文件输入的例子

 1 #在mac系统上不能直接操作文件,需要关闭或使用程序写入文件
 2 import time
 3 def listen_file():
 4     with open('userinfo') as f:
 5         while True:
 6             line = f.readline()
 7             if line.strip():
 8                 yield line.strip()
 9             time.sleep(0.1)
10 
11 g = listen_file()
12 for line in g:
13     print(line)

例3:send关键字

 1 def func():
 2     print(11111)
 3     ret1 = yield 1
 4     print(22222,'ret1 :',ret1)
 5     ret2 = yield 2
 6     print(33333,'ret2 :',ret2)
 7     yield 3
 8 
 9 g = func()
10 ret = next(g)#第一次使用生成器时不能用send执行
11 print(ret)
12 #>>>11111
13 #>>>1
14 print(g.send('alex'))  # 在执行next的过程中 传递一个参数 给生成器函数的内部
15 #>>>22222 ret1 : alex
16 #>>>2
17 print(g.send('金老板'))
18 #>>>33333 ret2 : 金老板
19 #>>>3

备注:向生成器中传递值 有一个激活的过程 第一次必须要用next触发这个生成器

例4:计算移动平均值

 1 # 计算移动平均值
 2 # 月度 的 天平均收入
 3 def average():
 4     sum_money = 0
 5     day = 0
 6     avg = 0
 7     while True:
 8         money = yield avg
 9         sum_money += money
10         day += 1
11         avg = sum_money/day
12 
13 g = average()
14 next(g)#得到一个0
15 print(g.send(200))#>>>200.0
16 print(g.send(300))#>>>250.0
17 print(g.send(600))#>>>366.6666666666667

 2、预激生成器

作用:当程序中的多个函数都需要预激活,那么就可以交给装饰器来解决

 1 def init(func):
 2     def inner(*args,**kwargs):
 3         ret = func(*args,**kwargs)
 4         next(ret)  # 预激活
 5         return ret
 6     return inner
 7 
 8 @init
 9 def average():
10     sum_money = 0
11     day = 0
12     avg = 0
13     while True:
14         money = yield avg
15         sum_money += money
16         day += 1
17         avg = sum_money/day
18 
19 g = average()
20 print(g.send(200))
21 print(g.send(300))
22 print(g.send(600))

3、yield from (python3中的用法)

 1 def generator_func():
 2     yield from range(5)
 3     yield from 'hello'
 4 #与下列代码相同
 5     # for i in range(5):
 6     #     yield i
 7     # for j in 'hello':
 8     #     yield j
 9 
10 g = generator_func()
11 for i in generator_func():#与for i in g:相同
12     print(i)
13 
14 g = generator_func()
15 while True:
16     print(generator_func())#会报错,每一次执行此函数都会生成一个新的生成器
17 g1 = generator_func()
18 g2 = generator_func()
19 next(generator_func())
20 next(generator_func())

4、如何从生成器中取值

1 # 第一种 :next  随时都可以停止 最后一次会报错
2 print(next(g))
3 print(next(g))
4 # 第二种 :for循环 从头到尾遍历一次 不遇到break、return不会停止
5 for i in g:
6     print(i)
7 # 第三种 :list tuple 数据类型的强转  会把所有的数据都加载到内存里 非常的浪费内存
8 print(g)
9 print(list(g))

5、总结

 1 # 生成器函数 是我们python程序员实现迭代器的一种手段
 2 # 主要特征是 在函数中 含有yield  不建议使用return
 3 # 调用一个生成器函数 不会执行这个函数中的带码 只是会获得一个生成器(迭代器)
 4 # 只有从生成器中取值的时候,才会执行函数内部的带码,且每获取一个数据才执行得到这个数据的带码
 5 # 获取数据的方式包括 next send 循环 数据类型的强制转化
 6 # yield返回值的简便方法,如果本身就是循环一个可迭代的,且要把可迭代数据中的每一个元素都返回 可以用yield from
 7 # 使用send的时候,在生成器创造出来之后需要进行预激,这一步可以使用装饰器完成
 8 # 生成器的特点 : 节省内存 惰性运算
 9 # 生成器用来解决 内存问题 和程序功能之间的解耦
10 #解耦:将功能性的代码进行尽量拆分,提交代码可读性,复用性

三、生成器表达式

 1 # 列表推倒式
 2 #求平方,然后存放到列表中
 3 #方式1
 4 new_lst = []
 5 for i in range(10):
 6     new_lst.append(i**2)
 7 print(new_lst)
 8 #方式2
 9 print([i**2 for i in range(10)])
10 #求2的余数,然后存放放列表中
11 l = [1,2,3,-5,6,20,-7]
12 print([i%2 for i in range(10)])
13 #找出所有的奇数,然后存放放列表中
14 l = [1,2,3,-5,6,20,-7]
15 print([num for num in l if num%2 == 1])
16 
17 # 30以内所有能被3整除的数
18 print([i for i in range(30) if i%3 ==0])
19 
20 # 30以内所有能被3整除的数的平方
21 print([i**2 for i in range(30) if i%3 ==0])
22 
23 # 找到嵌套列表中名字含有两个‘e’的所有名字
24 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
25          ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
26 print([name for name_lst in names for name in name_lst if name.count('e') == 2])
27 
28 # 生成器表达式
29 l = [i for i in range(30) if i%3 ==0]   # 列表推倒式 排序的时候
30 g = (i for i in range(30) if i%3 ==0)   # 生成器表达式 庞大数据量的时候 使用生成器表达式
31 print(l)#>>>[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
32 print(g)#>>><generator object <genexpr> at 0x000002A16630B8E0>
33 for i in g:print(i)

四、面试题

 1 # 面试题1
 2 # def demo():
 3 #     for i in range(4):
 4 #         yield i
 5 #
 6 # g=demo()
 7 #
 8 # g1=(i for i in g)
 9 # g2=(i for i in g1)
10 #
11 # print(list(g1))#>>>[0, 1, 2, 3]
12 # print(list(g2))#>>>[]
13 
14 
15 # 面试题2
16 # def add(n,i):
17 #     return n+i
18 #
19 #
20 # def test():
21 #     for i in range(4):
22 #         yield i
23 #
24 # g=test()
25 # for n in [1,10]:
26 #     g=(add(n,i) for i in g)
27 #
28 # print(list(g))#>>>[20, 21, 22, 23]
29 
30 
31 # 一个生成器 只能取一次
32 # 生成器在不找它要值的时候始终不执行
33 # 当他执行的时候,要以执行时候的所有变量值为准

 

posted on 2018-04-27 00:20  xingyemdd  阅读(165)  评论(0)    收藏  举报