Python学习笔记十四(多任务、协程、迭代器、生成器)

迭代[1]

什么是迭代

遍历取值的过程叫做迭代。

可迭代对象[2]

可以被for循环遍历取值的对象叫做可迭代对象。包括字符串(str)、列表(list)、元组(tuple)、字典(dict)、集合(set)、range等。

自定义可迭代对象

需要在类里面提供iter方法,然后此类的实例对象就是可迭代对象


from collections import Iterable


class CustomClass(object):
    def __iter__(self):
        pass


def main():
    """入口函数"""
    custom = CustomClass()

    # 判断CustomClass类的实例对象是不是可迭代对象
    print("CustomClass类的实例对象是不是可迭代对象: ", isinstance(custom, Iterable))


if __name__ == '__main__':
    main()
    
#运行结果:
#CustomClass类的实例对象是不是可迭代对象:  True


魔法方法__iter()__ 需要一个返回值,否则对custom 进行遍历 报错


for i in custom: 
        print(i)

# 运行结果:
# Traceback (most recent call last):
#   File "/home/python/Desktop/day/mode1.py", line 22, in <module>
#     main()
#   File "/home/python/Desktop/day/mode1.py", line 16, in main
#     for i in custom:
# TypeError: iter() returned non-iterator of type 'NoneType'

需要一个迭代器对象。

自定义迭代器对象

迭代器类需要提供__iter()__ 和 __next()__


from collections import Iterable

from collections import Iterator


class CustomClass(object):
    def __init__(self):
        super(CustomClass, self).__init__()
        # 提供存储数据的列表
        self.my_list = list()

    # 添加信息
    def append_item(self, item):
        self.my_list.append(item)

    # 提供可迭代对象方法
    def __iter__(self):
        # 可迭代对象之所以能够把数据迭代出来是通过迭代器完成的
        # 可迭代对象的本质是:通过迭代器把数据依次迭代出来
        custom_iterator = CustomIterator(self.my_list)
        result = isinstance(custom_iterator, Iterator)
        print("custom_iterator是否是迭代器:", result)
        return custom_iterator


# 自定义迭代器对象: 在类里面提供__iter__和__next__的方法创建的对象就是迭代器
# 迭代器的作用:记录数据的位置以便获取下一个位置的值
class CustomIterator(object):
    def __init__(self, my_list):
        self.my_list = my_list
        # 下标默认是0
        self.current_index = 0

    def __iter__(self):
        return self

    # 获取迭代器中下一个值
    def __next__(self):
        if self.current_index < len(self.my_list):
            result = self.my_list[self.current_index]
            self.current_index += 1
            return result
        else:
            # 表示下标越界, 抛出停止迭代的异常
            raise StopIteration


def main():
    """入口函数"""
    custom = CustomClass()

    # 添加数据
    custom.append_item(1)
    custom.append_item(2)
    custom.append_item(3)

    # for 循环内部自动捕获了StopIteration 异常
    for i in custom:
        print(i)


if __name__ == '__main__':
    main()

    # 运行结果:
    # custom_iterator是否是迭代器: True
    # 1
    # 2
    # 3

 

小结:

  • 迭代:一般来说就是使用 for循环,遍历取值的过程
  • 可迭代对象:可以被 for循环遍历取值的实例对象,或者类里面提供__iter()__ 方法的类的实例对象
  • 迭代器对象:类里面提供 __iter()__ 方法 和 __next()__ 方法的类的实例对象
  • 可迭代对象的本质:通过迭代器把数据依次迭代出来
  • 迭代器的作用:记录迭代的位置,以便获取下一个位置的数据。
  • __iter()__ 方法:调用可迭代对象的 __iter()__ 方法,获取可迭代对象的迭代器
  • __next()__ 方法:调用迭代器对象的 __next()__ 方法,获取迭代器中的下一个值。
  • for 循环的本质:
  • 遍历可迭代对象,通过可迭代对象的 __iter()__ 方法获取迭代器,然后通过迭代器的 __next()__ 方法,获取迭代器中的下一个值。
  • 遍历迭代器,直接通过迭代器的 __next()__ 方法,获取迭代器中的下一个值。
  • for 循环内部捕获了StopIteration 异常

生成器

什么是生成器

生成器是一类特殊的迭代器,既可以通过 for循环遍历取值,或者通过 next() 取值

生成器的创建

推导式


def main():
    """入口函数"""

    # 生成器的方式1,把列表推导式的中括号改成小括号创建的对象就是生成器
    generator = (i * 2 for i in range(10))

    for value in generator:
        print(value)


if __name__ == '__main__':
    main()


yieid 关键字


# 创建生成器方式2:在def里面看到有yield关键字那么就表示生成器


def func(num):
    current_index = 0
    print("--------1")
    # 循环判断条件是否成立
    while current_index < num:
        current_index += 1
        print("--------2")
        # 代码执行到yield会暂停,然后把结果返回出去, 再次启动生成器会在暂停的位置继续往下执行
        yield current_index
        print("--------3")


def main():
    """入口函数"""
    tmp = func(5)
    result = next(tmp)
    print(result)
    result = next(tmp)
    print(result)


if __name__ == '__main__':
    main()

# 运行结果
# --------1
# --------2
# 1
# --------3
# --------2
# 2


yieid 与 return

  • yieid 会暂停函数的运行,返回当前数据,执行 next方法,函数会从暂停的位置继续向下执行
  • return 会打断函数的运行,返回结果,再次运行函数,会从头开始重新执行
  • yieid 相同条件多次执行可以返回一组有关联的数据
  • return 相同条件多次执行返回同一结果
  • yieid 和 return 联用只有python3 支持,并且执行到return 会抛出StopIteration 异常
  • 除了next 可以启动生成器,send 也可以,send 启动可以传参,但是send 第一次启动生成器的传参必须为None,否则报错(TypeError: can't send non-None value to a just-started generator)

# 创建生成器方式2:在def里面看到有yield关键字那么就表示生成器


def func(num):
    current_index = 0
    print("--------1")
    # 循环判断条件是否成立
    while current_index < num:
        current_index += 1
        print("--------2")
        # 代码执行到yield会暂停,然后把结果返回出去, 再次启动生成器会在暂停的位置继续往下执行
        sned_value = yield current_index
        print("--------3")

        if sned_value > 3:
            return

        print("sned_value ", sned_value)


def main():
    """入口函数"""
    tmp = func(5)

    result = tmp.send(None)

    print(result)

    result = tmp.send(2)
    print(result)


if __name__ == '__main__':
    main()

    # 运行结果 
    # --------1
    # --------2
    # 1
    # --------3
    # sned_value 2
    # --------2
    # 2



协程

什么是协程

协程又称微线程,用户级线程,是Python 中实现多任务的方式之一。特点:在不开辟线程的基础上完成多任务

简单的协程

在 def 中有一个yieid 关键字,就是协程


import time


# 协程1
def func1():
    for i in range(5):
        print("func1...")
        time.sleep(0.2)
        yield


# 协程2
def func2():
    for i in range(5):
        print("func2...")
        time.sleep(0.2)
        yield


def main():
    """入口函数"""
    f1 = func1()
    f2 = func2()

    for i in range(5):
        next(f1)
        next(f2)


if __name__ == '__main__':
    main()

    # 运行结果
    # func1...
    # func2...
    # func1...
    # func2...
    # func1...
    # func2...
    # func1...
    # func2...
    # func1...
    # func2...

 

协程:在单线程的基础上可以完成多任务,多个任务按照一定顺序交替执行

greenlet 和 gevent

greenlet


# greenlet: greenlet框架封装的是yield,greenlet能够让程序员很直观的查看协程的切换
import time
import greenlet


# 任务1
def work1():
    for i in range(5):
        print("work1...")
        time.sleep(0.2)
        # 切换到协程2里面执行对应的任务
        g2.switch()


# 任务2
def work2():
    for i in range(5):
        print("work2...")
        time.sleep(0.2)
        # 切换到第一个协程执行对应的任务
        g1.switch()


if __name__ == '__main__':
    # 创建协程指定对应的任务
    g1 = greenlet.greenlet(work1)
    g2 = greenlet.greenlet(work2)

    # 切换到第一个协程执行对应的任务
    g1.switch()


gevent


import gevent
import time
from gevent import monkey

# 总结: gevent封装是greenlet,可以根据耗时操作自动完成协程之间的切换执行

# 打补丁,让gevent框架识别耗时操作,比如:time.sleep,网络请求延时
monkey.patch_all()


# 任务1
def work1():
    for i in range(10):
        print("work1....")
        time.sleep(0.2)
        # gevent.sleep(0.2)

# 任务1
def work2():
    for i in range(10):
        print("work2....")
        time.sleep(0.2)
        # gevent.sleep(0.2)
 

if __name__ == '__main__':
    # 创建协程指定对应的任务
    g1 = gevent.spawn(work1)
    g2 = gevent.spawn(work2)

    # 主线程等待协程执行完成以后程序再退出
    g1.join()
    g2.join()



进程、线程、协程

  • 进程是系统资源分配的基本单位,线程是CPU调度的基本单位,协程是在不开辟线程的基础上完成多任务
  • 进程资源开销大,稳定性强,效率很低;线程资源开销较小,稳定性较差,效率一般;协程资源开销小,稳定性依赖于线程,效率较高
  • 多进程,多线程可能是并行,但协程在一个线程中,所以是并发
  • 协程依赖于线程,线程依赖于进程。

进程就像是一个团队,团队有一些资源,线程是团队的成员,主线程就是team leader,协程就是团队中全栈工程师,哪里需要,去哪里。


到此结   DragonFangQy   2018.5.1


  1. 迭代

  2. Python 迭代对象、迭代器、生成器

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

推荐阅读更多精彩内容

  • 艾滋病一个陌生且熟悉的疾病,然而又有多少人能真正了解它呢 说实话其实我也不是很了解,但一次偶然的...
    Si0si阅读 630评论 0 2
  • 他不懂你的心假装冷静,他不懂爱情把它当游戏,他不懂你表明爱情这件事,他不懂你的心让你无法呼吸…… 每一次都...
    薄荷加冰要多心凉阅读 176评论 0 1
  • 大家好!我是322号星宝宝营养美容培训师祁爽,正在参加孙老师第13期蜕变之旅,这是我的第44篇原创日记我已经感觉到...
    营养美容培训师祁爽阅读 281评论 0 0
  • 人生有三次成长, 一次是发现自己不再是世界的中心的时候; 二是发现即使再怎么努力有些事也无能为力的时候; 三是就算...
    189期11组8号刘菲阅读 66评论 0 0