首页  >  问答  >  正文

程序设计 - 关于 Python 列表推导的疑惑

关于

Python list comprehension 其实就是 generator.

该怎么理解?

另外 map filter、generator 也让人挺不解的,求python 大牛都给解释下。这么设计的缘由是什么?

伊谢尔伦伊谢尔伦2713 天前334

全部回复(3)我来回复

  • 伊谢尔伦

    伊谢尔伦2017-04-17 13:46:40

    首先关于问题里面引用的那句话:不要这样理解,会把自己绕进去,而且也不准确。

    这个问题要往简单来看。对于一个简单的 list comprehension [x**2 for x in range(10)],它等价于:

    l = []
    
    for x in range(10):
        l.append(x**2)
    

    所以,list comprehension 只是一个语法糖,能让容器的初始化变得更加简洁,但它本质上还是在往容器里不断塞东西。(当然,由于这个语法存在,python 也可以针对性的优化性能,性能会比自己 append 好一些)

    List comprehensions provide a concise way to create lists.
    List comprehensions 提供了一种简洁明了的方式来创建 list
    来自 python 官方文档

    它跟 generator 概念不一样,如果要说的话,迭代器(iterator)可能才是描述 x**2 for x in range(10) 这种语法的正确方法,虽然它的名字确实叫做 generator expression。

    其次,什么是 generator。

    这个概念本身是很晦涩,如果初学不要强行理解。

    简单说它就是一个数据生成器,或者精确点说,它是个调用者可控的迭代器(iterator),仅此而已。

    Generator 函数就像一个扭蛋机,使用者每次投入一枚硬币它就吐出一颗扭蛋。

    • 扭蛋机不知道也不关心使用者是谁
    • 使用者不知道也不关心下次吐出的扭蛋是什么
    • 当使用想要扭蛋的时候就投币,立即就会出一个扭蛋,或者告诉他已经没有库存了
    • 当使用者不需要扭蛋的时候,他就可以一直无视这个扭蛋机

    这样设计的好处是,耦合低可控

    至于 generator 的高级用法,比如模拟 coroutine 什么的,可以暂时无视。

    最后,关于 mapfilter 等函数的设计思路。

    从 generator 的特性可以看出,它所能表达的只能是一种顺序输出的情况,无法后悔,除非从头开始。

    这就像一条工厂的流水线,只能向前不能后退。

    如果我们有这样一条流水线,我们能做什么呢?

    • 流水线的入口接着一个 generator,源源不断的从 generator 输出到流水线
    • 我们可以对流水线上的东西进行加工,一块钢板在上面锉一下变成某米的后盖,这就是 map
    • 我们可以把流水线上的残次品扔掉,这就是 filter

    流水线生产是工业时代智慧体现,能够将执行效率做到最高,并且流水线上各个环节都没有耦合性,它的合理性相当明显。

    回复
    0
  • PHPz

    PHPz2017-04-17 13:46:40

    这样处理主要是 Lazy 求值的做法

    设想一些应用场景,你需要对1000万个斐波那切数相加求和。

    • 一种方法是先用一个列表,写一个函数,直接生成1000万个个斐波那切数,然后再把1000万个存储,然后迭代这个list的每一个数进行叠加求和。(先生成,再处理)
    • 另外一种方式就是,写一个能按照要求,每次生成一个斐波那切数函数,求和的过程为每调用函数,生成一个斐波那切数,然后进行求和一次。(一边生成一遍处理)

    第二种方法,就是一种 lazy 的方式,也就是 python 惯用的 generator

    回复
    0
  • 天蓬老师

    天蓬老师2017-04-17 13:46:40

    不知道题主这句话是从何得来的,我测试的Python2.7就是转化成for函数而已如下.

    不知道Py3.*中是否也是如此(可能变了吧)

    回复
    0
  • 取消回复