• Python3高级特性(五)之容器(container)


    目录

    容器(container)

    迭代器(iterator)

    生成器(generator)

    生成器简介

    yield案例


    容器(container)

    容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中。

    在Python中,常见的容器对象有:

    1)      list, deque, ….

    2)      set, frozensets, ….

    3)      dict, defaultdict, OrderedDict, Counter, ….

    4)      tuple, namedtuple, …

    5)      str

    容器比较容易理解,因为可以把它看作是一个盒子,里面可以塞任何东西。从技术角度来说,当它可以用来询问某个元素是否包含在其中时,那么这个对象就可以认为是一个容器,比如 list,dict, set,tuples都是容器对象。

    容器是一系列元素的集合,str、list、set、dict、file、sockets对象都可以看作是容器,容器都可以被迭代(用在for,while等语句中),因此他们被称为可迭代对象。但凡是可以返回一个迭代器的对象都可称之为可迭代对象,

    迭代器(iterator)

    那么什么迭代器呢?它是一个带状态的对象,能在你调用next()方法的时候返回容器中的下一个值,任何实现了__iter__和__next__()方法的对象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常,至于它们到底是如何实现的这并不重要。迭代器就是实现了工厂模式的对象,它在每次询问要下一个值的时候给你返

    生成器(generator)

    生成器简介

    生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写__iter__()和__next__()方法了,只需要一个yiled关键字。

    生成器一定是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值。它特殊的地方在于函数体中没有return关键字,函数的返回值是一个生成器对象,只有显示或隐示地调用next的时候才会真正执行里面的代码。

    生成器在Python中是一个非常强大的编程结构,可以用更少地中间变量写流式代码,相比其它容器对象它更能节省内存和CPU,当然它可以用更少的代码来实现相似的功能。

    yield案例

    生成器对象是一个迭代器:但是它比迭代器对象多了一些方法,它们包括send方法,throw方法和close方法。这些方法,主要是用于外部与生成器对象的交互。

    send方法有一个参数:该参数指定的是上一次被挂起的yield语句的返回值。

    案例如下:

    1. def MyGenerator():
    2.     receive = yield 100
    3.     print('extra' + str(receive))
    4.     receive = yield 200
    5.     print('extra' + str(receive))
    6.     receive = yield 300
    7.     print('extra' + str(receive))
    8. gen = MyGenerator()
    9. print(next(gen))  #也可以用:print(gen.send(None))
    10. print("first")
    11. print(gen.send(2))
    12. print("second")
    13. print(gen.send(3))
    14. print("third")

    输出:100  first   extra2   200    second   extra3    300   third

    注意,yield语句是最具魔力的表达式:这里“yield 100”整体被视为一个表达式,send的内容会作为这个表达式的值,随便左边用什么变量接收或者不接收,总之yield就是send进来的那个值。这个表达式变成send进来后的那个值之后,继续往下执行,直到再次遇到yield,挂起。

    如何启动生成器呢?调用(gen.next()或gen.send(None))上面代码的运行过程如下。

    当调用gen.next()方法时:python首先会执行MyGenerator方法的yield 1语句。由于是一个yield语句,因此方法的执行过程被挂起,而next方法返回值为yield关键字后面表达式的值,即为100。

    当调用gen.send(2)方法时:python首先恢复MyGenerator方法的运行环境。同时,将表达式(yield 100)的返回值定义为send方法参数的值,即为2。这样,接下来value=(yield 100)这一赋值语句会将value的值设为2。继续运行会遇到yield value语句,MyGenerator方法再次被挂起。同时,send方法的返回值为yield关键字后面表达式的值,也即value的值,为200。

    当调用gen.send(3)方法时:首先恢复MyGenerator方法的运行环境。同时,将表达式(yield value)的返回值定义为send方法参数的值,即为3。这样,接下来value=(yield 200)这一赋值语句会将value的值置为3。继续运行,MyGenerator方法执行完毕。以此类推….

    总的来说:

    send方法和next方法唯一的区别,在执行send方法会首先把上一次挂起的yield语句的返回值通过参数设定,从而实现与生成器方法的交互。但是需要注意,在一个生成器对象没有执行next方法之前,由于没有yield语句被挂起,所以执行send方法会报错。当然,下面的代码是可以接受的:

    1. gen = MyGenerator() 
    2. print( gen.send(None) )

    因为当send方法的参数为None时,它与next方法完全等价。但是注意,虽然上面的代码可以接受,但是不规范。所以,在调用send方法之前,还是先调用一次next方法为好。

  • 相关阅读:
    工业I/O模块的功能和应用介绍
    麦芽糖-聚乙二醇-人血清白蛋白,HAS-PEG-maltose
    TMS320C6678开发板( DSP+Zynq )RTOS综合功能案例,嵌入式必看!
    Java多线程之线程池
    基于JAVA中文网络小说平台系统计算机毕业设计源码+系统+数据库+lw文档+部署
    【云原生】配置Kubernetes CronJob自动备份Clickhouse数据库(单机版)
    SDUT—Python程序设计实验五(列表与元组)
    【JavaWeb】Servlet系列——使用纯Servlet做一个单表的CRUD操作(实际操作实现篇)
    【Redis】五大基本数据类型操作大全
    数学之英文写作——基本中英文词汇(几何与三角的常用词汇)
  • 原文地址:https://blog.csdn.net/xiejiachao/article/details/125291942