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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值