BOO入门/Generators

BOO入门 > Generators (上一章:将函数当作物件与多执行绪 下一章:巨集)


Generator运算式 编辑

  定义 Generator运算式:以语法:<expression> for <declarations> [as <type>] in <iterator> [if|unless <condition>] 建立 generator 的语句。

Generator运算式很类似我们之前提过的 for 回圈,也具有相似的作用。 学习如何使用 Generator运算式的方法就是从例子里来学,所以请开启 booish:

$ booish
>>> List(x for x in range(5)) // 最簡單的 Generator 運算式
[0, 1, 2, 3, 4]
>>> List(x * 2 for x in range(5)) // 取得數值的兩倍
[0, 2, 4, 6, 8]
>>> List(x**2 for x in range(5)) // 取得數值的平方
[0, 1, 4, 9, 16]
>>> List(x for x in range(5) if x % 2 == 0) // 將所有偶數取出來
[0, 2, 4]
>>> List(x for x in range(10) if x % 2 == 0) // 將所有偶數取出來
[0, 2, 4]
>>> List(y for y in (x**2 for x in range(10)) if y % 3 != 0) // Generator運算式裡的Generator運算式
[1, 4, 16, 25, 49, 64]
>>> List(cat.Weight for cat in myKitties if cat.Age >= 1.0).Sort()  // 譯註,你會在這行遇到錯誤,請參考後面的說明。
[6.0, 6.5, 8.0, 8.5, 10.5]
>>> genex = x ** 2 for x in range(5)
generator(System.Int32)
>>> for i in genex:
...     print i
...
0
1
4
9
16

猫体重的范例(cat-weight),如你所见,很容易就能找到符合条件的小猫。(译注:这行无法运作,因为你没有 myKitties,如果要让这行能运行,请自己宣告一个类别,并加入 Weight、Age 属性,接著制作一个串列,放入数个这个类别的实体(object)。)

你不需要额外建立新串列,然后再一个一个去比对、放到新串列里。

generators 继承自 IEnumerable,所以你可以很容易地用回圈去寻访。

  建议 别用的太过火啦。如果他们让你代码不容易阅读的话,试著稍微扩展一下。(译注:简单的说,就是稍微想一下要怎么写会比较容易让人了解的意思。具体的方法有很多,例如使用 for 回圈或是下一节介绍的 Generator方法 ...)

Generator方法 编辑

  定义 Generator方法:在方法里使用 yield 关键字来建立 Generator 的方法。

Generator方法是一个能让你回传多次的正规作法。

这里有个 Generator方法能传回 2 的指数。

// Generator方法的範例
def TestGenerator():
    i = 1
    yield i
    for x in range(10):
        i *= 2
        yield i

print List(TestGenerator())

输出结果

[1, 2, 4, 8, 16, 32, 64, 128, 512, 1024]

Generator方法很有威力,因为能在 yield 之后在记忆体里保存所有的区域变数。这在其他语言也能见到(C# 里称为 Iterator,python 里也称为 Generator)。

总而言之,很有用。

练习 编辑

  1. 试著用Generator方法来作 fibonacci 数列。

课外参考 编辑