python学习day13 day14 迭代器 生成器

迭代器

可迭代的:

  • list
  • dic
  • str
  • set
  • tuple
  • f = open()
  • range()
  • enumerate
# 显示列表所拥有的所有方法
print(dir([])) 

双下方法:很少直接调用的方法,一般情况下,是通过其他语法触发的 

 

只要是能被for循环的数据类型 就一定拥有__iter__方法

一个可迭代的对象加上__iter__之后就是一个迭代器

  • 迭代器的三个方法:
'__setstate__'从某个位置取值  
'__next__'一个一个取值
'__length_hint__'元素个数

Iterable 可迭代的 -- > __iter__ 只要含有__iter__方法的都是可迭代的
[].__iter__() 这就是迭代器 -- > __next__ 通过next就可以从迭代器中一个一个的取值

 

可迭代协议:只要含有__iter__方法的都是可迭代的

迭代器协议:内部含有__next__和__iter__方法的就是迭代器

#定义一个迭代器类型
class A:  
    def __iter__(self):pass
    def __next__(self):pass

a = A()
print(isinstance(a,Iterator))  #迭代器
print(isinstance(a,Iterable))  #可迭代
  • 迭代器协议和可迭代协议

可以被for循环的都是可迭代的
可迭代的内部都有__iter__方法
只要是迭代器 一定可迭代
可迭代的.__iter__()方法就可以得到一个迭代器
迭代器中的__next__()方法可以一个一个的获取值

  • 判断是否是迭代器或可迭代对象:

for循环本质就是在使用迭代器
iterator
可迭代对象
直接给你内存地址
print([].__iter__())
print(range(10)) 也是迭代器

  • for

只有 是可迭代对象的时候 才能用for
当我们遇到一个新的变量,不确定能不能for循环的时候,就判断它是否可迭代:# print(dir([]))

  • 迭代器的好处:

从容器类型中一个一个的取值,会把所有的值都取到,只能取一次。

节省内存空间 ,迭代器并不会在内存中再占用一大块内存,而是随着循环 每次生成一个每次next每次给我一个

生成器

                          —— 本质是迭代器

  • 生成器函数
  • 生成器表达式

 

生成器函数 —— 本质上就是我们自己写得函数

def generator():
    # print(1)
    yield 'a'

只要含有yield关键字的函数都是生成器函数
yield不能和return共用 且需要写在函数内

 

生成器函数定义之后的执行:

ret = generator()  # 只是一个生成器
print(ret.__next__())  #一次一次执行生成器

应用:

# 监视文件的输入 当输入的行中含有'python'时,打印出来:

def tail(filename):
    f = open(filename,encoding='utf-8')
    while True:
        line = f.readline()
        if line.strip():
            yield line.strip()

g = tail('file')
for i in g:
    if 'python' in i:
        print('***',i)

生成器函数进阶

send:

  • send的作用范围和next一模一样
  • 第一次不能用send
  • 函数中的最后一个yield不能接受行的值
def generator():
    print(123)
    content = yield 1
    print('***' + content)
    print(456)
    yield 2

g = generator()

g.__next__()  # 返回1,指针停留在yield 1处,
ret = g.send('fan')  # 将值传给content
print(ret) #123 'fan' 456 2

 

 

应用:获取移动平均值:

引用了预激生成器的装饰器

# 装饰器函数的作用是执行g.__next__() 预激活 
def init(func):   #装饰器
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)    #g = average()
        g.__next__()
        return g
    return inner

@init
def average():
    sum = 0
    count = 0
    avg = 0
    while True:
        num = yield avg
        sum += num    # 10
        count += 1    # 1
        avg = sum/count

avg_g = average()   #===> inner
ret = avg_g.send(10)
print(ret)
ret = avg_g.send(20)
print(ret)

 

 

yield from

def generator():
    a = 'abcde'
    b = '12345'
    for i in a:
        yield i
    for i in b:
        yield i

'''
上下两个生成器是一样的
'''
def generator():
    a = 'abcde'
    b = '12345'
    yield from a
    yield from b

g = generator()
for i in g:
    print(i)

 

列表推导式 

egg_list=['鸡蛋%s'%i for i in range(10)]    #列表推导式
print(egg_list)

egg_list = []
for i in range(10):
    egg_list.append('鸡蛋%s'%i)
print(egg_list)

 

生成器表达式

g = (i for i in range(10))
print(g)  # 生成器

# 输出生成器
for i in  g:
    print(i)

g = (i*i for i in range(10))
g.__next__()

 

生成器表达式和列表推导式的区别:

  • 括号不一样
  • 返回的值不一样  ===几乎不占内存

 

各种推导式

[每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型] #遍历之后挨个处理
[满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素满足的条件] #筛选功能

# 30以内所有能被3整除的数的平方
ret = [i*i for i in (1,2,3,4) if i%3 == 0]
ret = (i*i for i in range(30) if i%3 == 0)
print(ret)


# 例三:找到嵌套列表中名字含有两个‘e’的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
ret = [name for lst in names for name in lst if name.count('e') ==2] # 先外面的 再里面的
ret = (name for lst in names for name in lst if name.count('e') ==2)  # 生成器列表
print(ret)

 

字典推导式

# 例一:将一个字典的key和value对调
mcase = {'a': 10, 'b': 34}
#{10:'a' , 34:'b'}
mcase_frequency = {mcase[k]: k for k in mcase}  # 遍历key
print(mcase_frequency)

# 例二:合并大小写对应的value值,将k统一成小写
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
#{'a':10+7,'b':34,'z':3}
mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase}  # mcase.get(k,0) 找不到的话,返回0
print(mcase_frequency)

 

集合推导式

# 自带去重功能
squared = {x**2 for x in [1, -1, 2]}
print(squared)  #{1,4}

 

没有元组推导式

 

面试题:

def demo():
    for i in range(4):
        yield i

g=demo()

g1=(i for i in g)
g2=(i for i in g1)

print(list(g))   #[0,1,2,3]  列出了生成器的东西
print(list(g1))  #[]  g1找g要值 g已经将demo中的值取完了 所以是空
print(list(g2))  #[]   同上

 

def add(n,i):
    return n+i

def test():
    for i in range(4):
        yield i

g=test()
for n in [1,10,5]:
    g=(add(n,i) for i in g)
## 拆开
# n = 1
# g=(add(n,i) for i in test())
# n = 10
# g=(add(n,i) for i in (add(n,i) for i in test()))
# n = 5
# g=(add(n,i) for i in (add(n,i) for i in (add(n,i) for i in test())))
# 只执行最后一句n=5的语句

print(list(g)) #[15,16,17,18]

 

posted @ 2018-10-30 15:09  xyfun72  阅读(136)  评论(0编辑  收藏  举报