Pythonでライザップしてみた

はじめに

PythonでFizzBuzzしてみたが思ったより反響が良かったので、Pythonでなにかアルゴリズムっぽいことをする記事を書くことにしました。

今回は、n回ごとにオンオフを切り替えるスイッチをジェネレーターで実装し、このスイッチをつかってライザップジェネレーターを作りましょう。

n回施行ごとにスイッチを切り替えるスイッチをつくろう

計算でi番目がオンかオフかを求める

今回の演算は、Pythonの/演算子の左辺と右辺が両方とも整数だった場合、整数を返す性質を利用しています。 連続した整数の場合、i/nでnごとに1増えるようになります。

n = 3
m = 10
for i in range(m):
    print i, i/n, i/n%2, ~i/n%2
==
0 0 0 1
1 0 0 1
2 0 0 1
3 1 1 0
4 1 1 0
5 1 1 0
6 2 0 1
7 2 0 1
8 2 0 1
9 3 1 0

ジェネレーター

ジェネレーターは関数のような形で定義し、yield文で返したところで、関数の処理が止まってくれるというものです。

def gen():
  yield 8382
  yield "hello"
  yield 1.42

g = gen()
print g.next() # 8382
print g.next() # "hello"
print g.next() # 1.42

たとえば、このようなジェネレータが作れます。
リスト何らかの理由で、これらを順番に取り出したい場合などに役立ちます。

スイッチ

それでは、今までの知識を組み合わせてスイッチを作ります。

def switch(n, init = False):
    i = 0
    while True:
        if init:
            yield ~i/n%2
        else:
            yield i/n%2
        i += 1

第一引数nは何回おきにスイッチを切り替えるかを整数で指定するものです。 第二引数initは初期状態でTrue・Falseのどちらを返すかを指定します。デフォルトでFalseで省略可能です。 関数内では、while True:で無限ループを実装して、先の演算をyieldすることで、nごとにオンオフを切り替えるスイッチを実装しています。

ライザップしよう

ライザップ・ジェネレータは、4回おきに、「ブウィッチ」と「テーデーツテッテ」を切り替えればいいので内部にさきほどつくったswitchジェネレータを作ります。
ライザップ・ジェネレータは、はじめに「ブウィッチ」を返したいので、作成するswitchジェネレータの第二引数は省略します。

def raizapGen():
    s = switch(4)
    while True:
        if s.next():
            yield u"テーデーツテッテ"
        else:
            yield u"ブウィッチ"

先ほどと同様に内部にwhile True:で無限ループにします。

これで、ライザップ・ジェネレータの完成です。

完成品

timeモジュールをインポートして、CMと同じタイミングで、プログラムが進行するようにしました。
絵文字は、結果がつまらなくなるのがこわかったので使いました。

まとめ

いい感じで、Pythonの数値演算の特性とジェネレータの使い方を紹介できたかと思います。

個人的には、「ブウィッチ」、「テーデーツテッテ」よりもしっくりくるのがあると思うので、ぜひGistからフォークしてオリジナルのライザップをつくっていただけたらと思います。