python3可迭代对象、迭代器、生成器、协程yield入门

技术交流QQ群:1027579432,欢迎你的加入!

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2019-01-24 16:13:07
# @Author  : cdl (1217096231@qq.com)
# @Link    : https://github.com/cdlwhm1217096231/python3_spider
# @Version : $Id$

# 1.可迭代、生成器、迭代器
"""
可迭代对象:字符串、list、tuple、dict、deque等
验证是否是可迭代对象、生成器、迭代器的方法,使用isinstance()方法
"""
import collections
from collections.abc import Iterable, Iterator, Generator

# 字符串

ss = "NJUST"
print("字符串:{}".format(ss))
print("是否是可迭代对象:{}".format(isinstance(ss, Iterable)))
print("是否是迭代器:{}".format(isinstance(ss, Iterator)))
print("是否是生成器:{}".format(isinstance(ss, Generator)))
print()

# list

lis = [23, 'haha', "cat", 666]
print("列表:{}".format(lis))
print("是否是可迭代对象:{}".format(isinstance(lis, Iterable)))
print("是否是迭代器:{}".format(isinstance(lis, Iterator)))
print("是否是生成器:{}".format(isinstance(lis, Generator)))
print()

# 字典dict

dic1 = {"Curry": "USA", "Yao": "China", "诺维斯基": "Germany"}
print("字典:{}".format(dic1))
print("是否是可迭代对象:{}".format(isinstance(dic1, Iterable)))
print("是否是迭代器:{}".format(isinstance(dic1, Iterator)))
print("是否是生成器:{}".format(isinstance(dic1, Generator)))
print()
# deque
de = collections.deque("abcdefg")
print("deque:{}".format(de))
print("是否是可迭代对象:{}".format(isinstance(de, Iterable)))
print("是否是迭代器:{}".format(isinstance(de, Iterator)))
print("是否是生成器:{}".format(isinstance(de, Generator)))
print()
# 总结:所有的可迭代对象都不是迭代器和生成器,但都可以用for循环进行遍历;可迭代对象其内部实现了一个__iter__()魔法方法
# 可以通过dir()方法来查看是否有__iter__()来判断一个变量是否是可迭代对象


# 2.迭代器(与可迭代对象相比,内部函数实现仅仅多了一个__next__()函数)
# 可以不使用for循环来获取元素,可以直接使用next()方法来实现
"""
迭代器是在可迭代对象的基础上实现的,要创建一个迭代器,首先必须要有一个可迭代对象,所以下面是介绍如何创建一个可迭代对象,并用创建的可迭代对象创建一个迭代器。
"""


class MyList(object):  # 定义可迭代对象类
    def __init__(self, num):
        self.end = num  # 上界
    # 返回一个实现了__iter__()和__next__()的迭代器类的实例

    def __iter__(self):
        return MyListIterator(self.end)


class MyListIterator(object):  # 定义迭代器类
    def __init__(self, end):
        self.data = end  # 上界
        self.start = 0

    # 返回该对象的迭代器类的实例,因为自己就是迭代器,所以返回self
    def __iter__(self):
        return self
    # 迭代器必须实现的方法

    def __next__(self):
        while self.start < self.data:
            self.start += 1
            return self.start - 1
        raise StopIteration


my_list = MyList(5)  # 得到一个可迭代对象
print(isinstance(my_list, Iterable))
print(isinstance(my_list, Iterator))
# 迭代
for i in my_list:
    print(i)
my_iterator = iter(my_list)  # 得到一个迭代器对象
print("是否是可迭代对象:{}".format(isinstance(my_iterator, Iterable)))
print("是否是迭代器:{}".format(isinstance(my_iterator, Iterator)))
# 迭代
print(next(my_iterator))
print(next(my_iterator))
print(next(my_iterator))
print(next(my_iterator))
print(next(my_iterator))


astr = "abcd"  # 创建字符串,它可以是可迭代对象
aIterator = iter(astr)  # 通过iter()方法,将可迭代对象转化为迭代器
print(isinstance(aIterator, Iterator))
print(next(aIterator))
print(next(aIterator))
print(next(aIterator))
print(next(aIterator))
# 总结:迭代器其内部实现了__next__()这个魔法函数,可以通过dir()方法来查看变量是否是迭代器


# 3.生成器generator:为了实现一个在计算下一值时不需要浪费空间的结构。生成器是在迭代器的基础上(可以使用for循环和next())再实现了yield,yield相当于函数中的return,在每次next()或者进行for循环时,都会在yield这里将新的值返回回去,并在这里阻塞,等待下一次的调用。实现节省内存,实现异步编程。

# 创建一个生成器有两种方法:改进版的列表生成式和实现yield的函数
# (1).使用改进版的列表生成式,注意不是[],而是()
L = (x**2 for x in range(10))
print("L是一个函数对象:{}".format(L))
print(isinstance(L, Generator))
print("将生成器对象转换成list进行输出:{}".format(list(L)))
# (2).实现yield的函数


def my_generator(n):
    now = 0
    while now < n:
        yield now
        now += 1


gen = my_generator(10)  # 生成器对象
print("生成器对象:%s" % gen)
print(isinstance(gen, Generator))
print(list(gen))

# 总结:可迭代对象和迭代器,是将所有的值都生成后再存放在内存中,而生成器则是把需要的元素临时生成,节省时间与空间。

# 4.运行和激活生成器
# 由于生成器并不是一次生成所有元素,而是一次一次的执行返回,激活生成器执行的两种方法:next()和generator.send(None)


def mygen(n):
    now = 0
    while now < n:
        yield now
        now += 1


gen = mygen(4)
# 通过交替执行,来说明这两种方法是等价的
print(gen.send(None))
print(next(gen))
print(gen.send(None))
print(next(gen))

# 5.生成器的执行状态
# 生成器在其生命周期中,会有4个状态:gen_created等待开始执行--->gen_running解释器正在执行(多线程应用中才能看到该状态)--->gen_suspend在yield表达式处暂停--->gen_closed执行结束
from inspect import getgeneratorstate


def gen(n):
    now = 0
    while now < n:
        yield now
        now += 1


gen = gen(2)
print(getgeneratorstate(gen))  # created

print(next(gen))
print(getgeneratorstate(gen))  # suspend

print(next(gen))
gen.close()
print(getgeneratorstate(gen))  # close

# 6.生成器的异常处理
# 在生成器工作过程中,如果生成器不满足生成元素的条件,就会抛出异常StopIteration


def gen1(n):
    now = 0
    while now < n:
        yield now
        now += 1
    raise StopIteration   # 抛出异常


gen = gen1(2)
print(next(gen))
print(next(gen))
# print(next(gen))

# 7.从生成器过渡到协程yield
# 在生成器暂停的时候向其发送一点东西,协程与线程有很多类似点:多个协程之间只会交叉串行执行;不同点:线程之间要频繁进行切换、加锁、解锁,从复杂度和效率上来看,比协程麻烦。协程通过使用yield暂停生成器,可以将程序的执行流程交给其他的子程序,从而实现不同子程序之间的交替执行。


def jump_range(N):
    index = 0
    while index < N:
        # 通过send()发送的信息将赋值给jump
        jump = yield index  # yield index是将index返回给外部调用程序;jump = yield可以接收外部程序通过send()发送的信息,并赋值给jump
        if jump is None:
            jump = 1
        index += jump


itr = jump_range(5)
print(next(itr))
print(itr.send(2))
print(next(itr))
print(itr.send(-1))

参考文章链接

python编程时光

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