python--迭代器与生成器;列表推导式,生成器表达式,各种推导式

一,迭代器

1.1什么是可迭代对象?

(字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。)

什么是可迭代对象:内部含有__iter__方法的对象就叫做可迭代对象

可迭代对象就遵循可迭代协议。

1.2判断迭代对象的两种方法:

第一种:print("__iter__" in dir(object))  dic()  查看数据类型的所有方法。

第二种:from collections import Iterable

    print(isinstance(objcet,Iterable))  #返回True 就是

    或者

    from collections import Iterator

    print(isinstance(objcet,Iterator))

1.3迭代器

将可迭代对象转化成迭代器:可迭代对象.__iter__()

 

1,将可迭代对象转化成迭代器
2,内部使用__next__方法取值
3,运用了异常处理去处理报错。

 

1.4迭代器的属性

迭代器不仅含有__iter__,还包含__next__。遵循迭代器协议。

判断迭代器的方法:

  print('__iter__' in dir(l1_obj))
  print('__next__' in dir(l1_obj))
  from collections import Iterator
  print(isinstance(l1_obj, Iterator))

while循环模拟for循环的机制。

li = [4,5,6,7,43,3,2]
li_obj = li.__iter__()
while True:
    try:
        m = li_obj.__next__()
        print(m)
    except Exception:
        break

 

1.5迭代器的好处:

1.节省内存空间

2.满足惰性机制

3.不能反复取值,不可逆。

 二,生成器Generator

2.1初始生成器

  一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

  我们知道的迭代器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存。

  如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器。

生成器Generator:

  本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

  特点:惰性运算,开发者自定义

2.2生成器的产生方式

1,生成器函数构造。
2,生成器推导式构造。

2.3函数构造,生成器

def func():

  print(111)

  print(222)

  print(333)

  yield 666

  yield 555

  yield 777

g = func()

第一:函数中只要有yield 那他就不是一个函数,而是一个生成器
第二:g称作生成器对象。

2.4关键字 send

send 获取下一个值的效果和next基本一致
只是在获取下一个值的时候,给上一yield的位置传递一个数据
使用send的注意事项
第一次使用生成器的时候 是用next获取下一个值
最后一个yield不能接受外部的值
from functools import wraps

def init(func):  #在调用被装饰生成器函数的时候首先用next激活生成器
    @wraps(func)
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)
        next(g)
        return g
    return inner

@init
def averager():
    '''
    这是一个计算平均移动速度的函数
    :return: 移动速度值
    '''
    total = 0.0
    count = 0
    average = None
    while True:
        term = yield average
        total += term
        count += 1
        average = total/count


g_avg = averager()
# next(g_avg)   在装饰器中执行了next方法
print(g_avg.send(10))
print(g_avg.send(30))
print(g_avg.send(5))
print(averager.__doc__)
print(averager.__name__)
计算移动平均值(2)_预激协程的装饰器
def gen1():
    for c in 'AB':
        yield c
    for i in range(3):
        yield i

print(list(gen1()))

def gen2():
    yield from 'AB'
    yield from range(3)

print(list(gen2()))
yield from
 面试题一: 一个生成器只能取一次值
def demo(): # 1- 定义生成器函数demo
    for i in range(4):
        yield i

g=demo() # 2- 调用demo函数,不会执行这个函数中的代码,只会获得一个生成器(迭代器)

g1=(i for i in g) # 3- 本质是利用生成器表达式创建生成器函数,不会执行这个函数中的代码,只会获得一个生成器(迭代器)
g2=(i for i in g1) # 4- 本质是利用生成器表达式创建生成器函数,不会执行这个函数中的代码,只会获得一个生成器(迭代器)

print(list(g1)) # 5- 开始取值,向g1要值,g1是一个生成器,g1向g要值,g也是一个生成器,g向demo要值,demo会给g1 -- 0,1,2,3
print(list(g2)) # 6- g2是一个生成器,向g1要值,g1向g要值,g也是一个生成器,g向demo要值,此时demo中的值已经被取完了
# [0, 1, 2, 3]
# []
面试题一
# 面试题二 生成器在不找它要值的时候始终不执行
# 当它执行的时候,要以执行时候的所有变量值为准
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)

print(list(g))

-------------------------------------------------

# 将for循环转化为非循环代码
# for n in [1,10]:
#     g=(add(n,i) for i in g)
# 转化为
# n = 1
# g=(add(n,i) for i in g)
# n = 10
# g=(add(n,i) for i in g)
# 因为生成器表达式只是创建生成器函数,***不会执行这个函数中的代码***
# 只会获得一个生成器(迭代器)g,这个g就是n=10的时候括号里for循环中的g
# 所以list(g)中的g为n=10的时候的值,下面是推导过程
n = 10
# g=(add(n,i) for i in g)
# g=(add(n,i) for i in (add(n,i) for i in test()))
# g=(add(n,i) for i in (add(n,i) for i in [0,1,2,3]))
# g=(add(10,i) for i in (add(10,i) for i in [0,1,2,3]))
# g=(add(10,i) for i in (10,11,12,13))
g=(20,21,22,23)
print(list(g))
# [20, 21, 22, 23]
面试题二

三、列表推导式

1.li = [i for i in range(1,101)]
print(li)
2.
multiples = [i for i in range(30) if i % 3 is 0]  #可加判断条件
print(multiples)
3.
li = [i for i in range(1,10)]升级:前面的i可以添加三元运算:
li = [i if i < 5 else i*i for i in range(10)]
4.
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]

print([name for lst in names for name in lst if name.count('e') >= 2])  # 注意遍历顺序,这是实现的关键
列表推导式,嵌套循环

 5.将一个字典的key和value对调  字典生成式

1.把列表解析的[]换成()得到的就是生成器表达式


2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

根据value值来排序字典的keys

>>> d = {'a': 7, 'c': 4, 'b': 3, 'd': 4, 'f': 6, 'e': 1}

>>> t = sorted([(v, k) for k, v in d.items()])
>>> print([k for v, k in t])
['e', 'b', 'c', 'd', 'f', 'a']

四、生成器表达式

li = [i for i in rang(1,101)]将列表推导式外面的[]变成(),就是一个生成器表达式。

li = (i for i in rang(1,101))

五、各种推导式

1、列表推导式

例一:30以内所有能被3整除的数

multiples = [i for i in range(30) if i % 3 is 0]
print(multiples)
# Output: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]

例二:30以内所有能被3整除的数的平方

def squared(x):
    return x*x
multiples = [squared(i) for i in range(30) if i % 3 is 0]
print(multiples)

例三:找到嵌套列表中名字含有两个‘e’的所有名字

names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]

print([name for lst in names for name in lst if name.count('e') >= 2])  # 注意遍历顺序,这是实现的关键

 2、字典推导式

例一:将一个字典的key和value对调

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

例二:合并大小写对应的value值,将k统一成小写

mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()}
print(mcase_frequency)
mcase.get(k.lower(), 0)  # 0是默认值,如果对应的key没有vlues就用0

3、集合推导式

例:计算列表中每个值的平方,自带去重功能

squared = {x**2 for x in [1, -1, 2]}
print(squared)
# Output: set([1, 4])

 

练习题:

例1:  过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母

例2:  求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表

例3:  求M中3,6,9组成的列表M = [[1,2,3],[4,5,6],[7,8,9]]

1.[name.upper() for name in names if len(name)>3]
2.[(x,y) for x in range(5) if x%2==0 for y in range(5) if y %2==1]
3. [row[2] for row in M] 


posted @ 2018-04-09 21:58  纸上得来终觉浅,  阅读(109)  评论(0)    收藏  举报