python--迭代器和生成器

2019-04-03  本文已影响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 已经不请求有这个文件,也可以导入。


上一篇下一篇

猜你喜欢

热点阅读