python--迭代器和生成器

推导表达式

在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 已经不请求有这个文件,也可以导入。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容