当前位置: 首页 > 面试题库 >

Python:生成器表达式与产量

柴晔
2023-03-14
问题内容

在Python中,通过 生成器表达式 创建生成器对象与使用 yield 语句之间有什么区别吗?

使用 yield

def Generator(x, y):
    for i in xrange(x):
        for j in xrange(y):
            yield(i, j)

使用 生成器表达式

def Generator(x, y):
    return ((i, j) for i in xrange(x) for j in xrange(y))

这两个函数都返回生成器对象,这些对象生成元组,例如(0,0),(0,1)等。

一个或另一个有什么优势吗?有什么想法吗?

谢谢大家!这些答案中有很多不错的信息和进一步的参考!


问题答案:

两者之间只有细微的差别。您可以使用该dis模块自己检查这种事情。

编辑: 我的第一个版本反编译了在交互式提示符下在module-
scope上创建的生成器表达式。这与在函数内部使用的OP版本略有不同。我已对此进行了修改,以匹配问题中的实际情况。

如下所示,“ yield”生成器(第一种情况)在设置中具有三个额外的指令,但与第一个指令相比,FOR_ITER它们仅在一个方面有所不同:“
yield”方法在循环内部使用LOAD_FAST代替LOAD_DEREF。的LOAD_DEREF是“而较慢的”比LOAD_FAST,所以它使得“产量”版本略快于对的足够大的值的生成器表达式x(外环),因为该值y是稍快于每遍加载。对于较小的值,x由于设置代码的额外开销,它会稍微慢一些。

值得指出的是,生成器表达式通常将在代码中内联使用,而不是将其与此类函数包装在一起。这将消除一些设置开销,并使生成器表达式对于较小的循环值稍快一些,即使在其他情况下LOAD_FAST给“
yield”版本带来了好处。

在任何一种情况下,性能差异都不足以证明在一个或另一个之间做出决定是合理的。可读性的重要性要大得多,因此请使用对当前情况最易读的方式。

>>> def Generator(x, y):
...     for i in xrange(x):
...         for j in xrange(y):
...             yield(i, j)
...
>>> dis.dis(Generator)
  2           0 SETUP_LOOP              54 (to 57)
              3 LOAD_GLOBAL              0 (xrange)
              6 LOAD_FAST                0 (x)
              9 CALL_FUNCTION            1
             12 GET_ITER
        >>   13 FOR_ITER                40 (to 56)
             16 STORE_FAST               2 (i)

  3          19 SETUP_LOOP              31 (to 53)
             22 LOAD_GLOBAL              0 (xrange)
             25 LOAD_FAST                1 (y)
             28 CALL_FUNCTION            1
             31 GET_ITER
        >>   32 FOR_ITER                17 (to 52)
             35 STORE_FAST               3 (j)

  4          38 LOAD_FAST                2 (i)
             41 LOAD_FAST                3 (j)
             44 BUILD_TUPLE              2
             47 YIELD_VALUE
             48 POP_TOP
             49 JUMP_ABSOLUTE           32
        >>   52 POP_BLOCK
        >>   53 JUMP_ABSOLUTE           13
        >>   56 POP_BLOCK
        >>   57 LOAD_CONST               0 (None)
             60 RETURN_VALUE
>>> def Generator_expr(x, y):
...    return ((i, j) for i in xrange(x) for j in xrange(y))
...
>>> dis.dis(Generator_expr.func_code.co_consts[1])
  2           0 SETUP_LOOP              47 (to 50)
              3 LOAD_FAST                0 (.0)
        >>    6 FOR_ITER                40 (to 49)
              9 STORE_FAST               1 (i)
             12 SETUP_LOOP              31 (to 46)
             15 LOAD_GLOBAL              0 (xrange)
             18 LOAD_DEREF               0 (y)
             21 CALL_FUNCTION            1
             24 GET_ITER
        >>   25 FOR_ITER                17 (to 45)
             28 STORE_FAST               2 (j)
             31 LOAD_FAST                1 (i)
             34 LOAD_FAST                2 (j)
             37 BUILD_TUPLE              2
             40 YIELD_VALUE
             41 POP_TOP
             42 JUMP_ABSOLUTE           25
        >>   45 POP_BLOCK
        >>   46 JUMP_ABSOLUTE            6
        >>   49 POP_BLOCK
        >>   50 LOAD_CONST               0 (None)
             53 RETURN_VALUE


 类似资料:
  • 问题内容: 什么时候应该使用生成器表达式,什么时候应该在中使用列表推导? 问题答案: John的答案很好(当你要迭代多次时,列表理解会更好)。但是,还应注意,如果要使用任何列表方法,都应使用列表。例如,以下代码将不起作用: 基本上,如果你要做的只是迭代一次,则使用生成器表达式。如果你要存储和使用生成的结果,那么列表理解可能会更好。 由于性能是选择彼此的最常见原因,所以我的建议是不要担心它,而只选择

  • Quartz 的Cron任务调度表达式一般人很难理解,在Googole上查询也没有发现类似的代码,所以开发了一个对Quartz Cron 表达式的可视化双向解析和生成的一个java的GUI程序,供使用Quartz的程序员参考和使用,源代码放在SourceForge网站

  • 本文向大家介绍python生成器表达式和列表解析,包括了python生成器表达式和列表解析的使用技巧和注意事项,需要的朋友参考一下 绝大多数情况下,遍历一个集合都是为了对元素应用某个动作或是进行筛选。如果看过本文的第二部分,你应该还记得有内建函数map和filter提供了这些功能,但Python仍然为这些操作提供了语言级的支持。 如你所见,生成器表达式和列表解析(注:这里的翻译有很多种,比如列表展

  • 本文向大家介绍python 中的列表生成式、生成器表达式、模块导入,包括了python 中的列表生成式、生成器表达式、模块导入的使用技巧和注意事项,需要的朋友参考一下 5.16 列表生成式 5.17 列表生成式与生成器表达式的应用 第六章模块 什么是模块? 模块就是一系统功能的集合体,在python中,一个py文件就是一个模块,比如module.py,其中模块名module 6.1 import

  • 本文向大家介绍python列表生成式与列表生成器的使用,包括了python列表生成式与列表生成器的使用的使用技巧和注意事项,需要的朋友参考一下 列表生成式:会将所有的结果全部计算出来,把结果存放到内存中,如果列表中数据比较多,就会占用过多的内存空间,可能会导致MemoryError内存错误或者导致程序在运行时出现卡顿的情况 列表生成器:会创建一个列表生成器对象,不会一次性的把所有结果都计算出来,如

  • 本文向大家介绍Python中的列表生成式与生成器学习教程,包括了Python中的列表生成式与生成器学习教程的使用技巧和注意事项,需要的朋友参考一下 列表生成式 即创建列表的方式,最笨的方法就是写循环逐个生成,前面也介绍过可以使用range()函数来生成,不过只能生成线性列表,下面看看更为高级的生成方式: 写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来,