在这个生命游戏实现中解释收益率的使用

oli*_*ren 3 python yield generator python-itertools conways-game-of-life

这次PyCon演讲中,杰克迪德里奇展示了康威生命游戏的这种"简单"实现.我对GoL或半高级Python并不熟悉,但代码似乎很容易掌握,如果不是两件事:

  1. 使用yield.我之前已经看到使用yield来创建生成器,但是它们中的8个是新的...它是否返回了8个生成器的列表,或者这个是如何工作的?
  2. set(itertools.chain(*map(neighbors, board))).这个明星将结果列表(?)从将邻居应用到董事会中解压缩,并且...我的思绪刚刚爆发.

是否有人试图为程序员解释这两个部分,这些程序员习惯于使用map,filter和reduce将一些python代码混合在一起,但是每天都不使用Python?:-)

import itertools

def neighbors(point):
    x, y = point
    yield x + 1, y
    yield x - 1, y
    yield x, y + 1
    yield x, y - 1
    yield x + 1, y + 1
    yield x + 1, y - 1
    yield x - 1, y + 1
    yield x - 1, y - 1

def advance(board):
    newstate = set()
    recalc = board | set(itertools.chain(*map(neighbors, board)))
    for point in recalc:
        count = sum((neigh in board) for neigh in neighbors(point))
        if count == 3 or (count == 2 and point in board):
            newstate.add(point)
    return newstate

glider = set([(0,0), (1,0), (2, 0), (0,1), (1,2)])
for i in range(1000):
    glider = advance(glider)
    print glider
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 11

生成器基于两个原则运行:它们在每次yield遇到语句时都会生成一个值,除非它被迭代,否则它们的代码会被暂停.

无论yield生成器中使用了多少语句,代码仍然以正常的python顺序运行.在这种情况下,没有循环,只有一系列yield语句,所以每次生成器进阶时,python都会执行下一行,这是另一个yield语句.

neighbors发电机会发生什么:

  1. 生成器始终开始暂停,因此调用neighbors(position)返回尚未执行任何操作的生成器.

  2. 当它被提前(next()在其上调用)时,代码将一直运行到第一个yield语句.首先x, y = point执行,然后x + 1, y计算并产生.代码再次暂停.

  3. 再次高级时,代码将一直运行,直到遇到下一个 yield语句.它产生了x - 1, y.

  4. 等等,直到功能完成.

set(itertools.chain(*map(neighbors, board)))行:

  1. map(neighbors, board)board序列中的每个位置生成一个迭代器.它只是循环遍历,调用neighbors每个值,并返回一个新的结果序列.每个neighbors()函数返回一个生成器.

  2. *parameter语法扩展parameter序列插入的参数的列表,就好象函数用的每个元素被称为在parameter作为代替一个单独的位置参数.param = [1, 2, 3]; foo(*param)会翻译成foo(1, 2, 3).

    itertools.chain(*map(..))获取由地图生成的每个生成器,并将其作为一系列位置参数应用于itertools.chain().循环链的输出意味着每个板位置的每个发生器按顺序迭代一次.

  3. 所有生成的位置都被添加到一个集合中,基本上删除了重复项

您可以将代码扩展为:

positions = set()
for board_position in board:
    for neighbor in neighbors(board):
        positions.add(neighbor)
Run Code Online (Sandbox Code Playgroud)

在python 3中,通过使用itertools.chain.from_iterable()代替,可以更有效地表达该行,因为map()在Python 3中也是一个生成器; .from_iterable()不会强制map()扩展,而是map()根据需要逐个循环结果.