美文网首页
python--迭代器和生成器

python--迭代器和生成器

作者: 昆仑草莽 | 来源:发表于2019-04-03 13:00 被阅读0次

    推导表达式

    在python中,想要得到 1-10 的数字我们可以怎么做呢。

    li = []
    for i in range(1,11):
        li.append(i)
    print(li)
    输出:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    

    其实,我们还有更加简洁的写法

    li = [i for i in range(1,11)]
    print(li)
    输出:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    

    这种方法叫做列表推导。列表推到还可以和很多方法一起使用。
    列表推导 + 条件判断

    li = [i for i in range(1,11) if i >5]
    print(li)
    输出:[6, 7, 8, 9, 10]
    li = [i for i in range(1,11) if i % 2 == 0]
    print(li)
    输出:[2, 4, 6, 8, 10]
    

    列表推导 + 三目运算

    li = [i*100 if i % 3 == 0 else i*10 for i in range(1, 10)]
    print(li)
    输出:[10, 20, 300, 40, 50, 600, 70, 80, 900]
    

    列表推导 + for 嵌套

    li = [i+j for i in range(1,5) for j in range(1,5)]
    print(li)
    输出:[2, 3, 4, 5, 3, 4, 5, 6, 4, 5, 6, 7, 5, 6, 7, 8]
    

    集合推导

    se = {i for i in range(1,10)}
    print(se)
    输出:{1, 2, 3, 4, 5, 6, 7, 8, 9}
    

    字典推导

    li = {'a','b','c'}
    dic = {i: j for j, i in enumerate(li)}  #enumerate 是枚举,所以下标与元素配对。
    print(dic)
    输出:{'c': 0, 'b': 1, 'a': 2}
    

    推导表达式相对于for循环来处理数据,要更加的方便,列表推导表达式使用更加的广泛,推导式还有很多用法,可以灵活的使用。

    迭代器和生成器

    列表推导式是往列表里写进数据,那么我们需要从列表中取出数据呢。首先,我们看看 for 循环在python的运行机制(底层运行方法)。

    for 迭代变量 in 可迭代对象:
    li = [1,2,3,4,5,6]
    for i in li:
        print(i)
    
    for  循环的底层运行机制
    index = 0
    var = None
    while index < len(li):
        var = li[index]
        print(var)
        index += 1
    

    每一次的循环,都会让迭代变量指向下一个元素。那么迭代对象和迭代器有什么区别呢。

    迭代器

    1.生成迭代器的方法

    iterator = iter(li)  #iter 的底层调用是python的__iter__()魔术方法。
    iterator = li.__iter__()  #使用python的魔术方法,生成迭代器
    

    2.迭代器本身需要支持以下两种方法,他们一起构成迭代器协议

    iterator.__iter__()
    iterator.__next__()
    

    3.取值

    next(iterator)
    iterator.__next__()
    注意:如果迭代器值取完之后,会返回 StopIteration 错误
    

    4.从可迭代对象生成一个迭代器

    迭代器 = iter(可迭代对象)
    下个值 = next(迭代器)
    

    现在,我们在看看 for 循环实现的原理

    iterable = [1,2,3,4,5]
    it = iter(iterable)  # 首先将可迭代对象变成迭代器
    while Ture:
        try:
            var = next(it)  #一个一个的取值
            print(var)
        except StopIteration:  #直到没有值,跳出循环
            break
    

    可见,for 循环时从迭代器中取值,是自动循环调用 next 方法的。所有不需要手动 next 取值。
    自定义迭代器:

    class TestIter:  #建立迭代器类
        def __init__(self,li):  #初始化类
            self.li = li
            self._index = 0
        def __iter__(self):  #建立迭代器
            return self
        def __next__(self):  #建立next魔术方法
            if self._index < len(self.li):
                index = self.li[self._index]
                self._index += 1
                return index
            else:
                raise StopAsyncIteration  #迭代器取完数据后抛出异常
    
    a = TestIter('abcdefg')
    while True:
        print(a.__next__())
    

    生成器

    生成器不会把所有内容一下全部生成出来,在我们需要的时候使用 next() 去生成。

    方法一:
    a = (x for x in range(1,11))
    print(next(a))
    输出:1
    print(next(a))
    输出:2
    print(next(a))
    输出:3
    注意:列表推导式的 [] 换成 ()
    
    方法二:
    def func(num):
        a = 0
        while a < num:
            yield a
            a += 1
    b = func(10)
    print(next(b))
    输出:0
    print(next(b))
    输出:1
    print(next(b))
    输出:2
    

    yield运行规则

    yield 一个对象
    暂停这个对象
    等待下一个next重新激活
    注意:
    yield 表达式只能在函数中使用
    yield 表达式可以使函数成为一个生成器
    yield 可以返回表达式结果,并且暂定函数执行,直到next激活下一个yield
    简单点理解生成器就是一个迭代器
    

    Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才
    产生结果,而不是立即产生结果,从而节省大量的空间,这也是生成器的主要好处

    补充:
    a = (x for x in range(1,11))
    print(dir(a))
    输出:['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', 
    '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', 
    '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', 
    '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', 
    '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
    'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']
    

    在dir(object) 查询中,有__ iter__魔法方法,且有__ next__魔法方法的就是迭代器,只有__ iter__魔法方法的是可迭代对象。

    模块,包管理器

    在python中,模块就是一个 .py 文件,可以使用下面两种方法导入。

    import datetime  #直接导入模块
    from datetime import datetime  #导入模块中的datetime功能
    import datetime as dt  #给datetime 取别名
    from datetime import datetime as dt
    

    导入模块调用的时候需要前面加上 包名.模块名 一层一层的加上,以 . 号分隔开。包的层级划分为:包 --> 模块 --> 库 --> 方法

    import time
    time.sleep()  #sleep前面是模块名字。
    

    在同一目录情况下导入,可以使用上面两种方法导入。在不同目录下导入,要添加绝对路径来添加。

    import 包.模块.库 
    直接调用方法
    from 包.库. 模块 import 方法
    直接调用方法
    import 包
    包.模块.库.方法
    

    在python中包内有一个 __ init__.py 文件,此时才可以导入,python3 已经不请求有这个文件,也可以导入。


    相关文章

      网友评论

          本文标题:python--迭代器和生成器

          本文链接:https://www.haomeiwen.com/subject/bypgbqtx.html