2019/02/16

Pythonで即席でcondを作ってみました

if文を最小限に抑える

前回書いたPythonに欲しい機能、Common Lispのcondですが、即席で考えて作ってみました。コードは以下のようになりました。
インデントはうまく表示されておりませんが、スペース4つです。

def cond(value, conditions, guard):
    exec(value)
    for test, form in conditions:
        if eval(test) is True:
            return form
            break
    else:
        return guard
そして使い方は以下のように、何となく見た目は似た感じに仕上がりました。

for i in range(16):
    print(cond(f"x = {i}", [
        ("x % 15 == 0", "FizzBuzz"),
        ("x % 5 == 0", "Buzz"),
        ("x % 3 == 0", "Fizz")
        ],
        i
    ))

とりあえずFizzBuzzはうまく結果を表示できました。execやらevalあたりを使用しているので、このままでは安全性はゼロと言っても過言ではないでしょう。
一応condの各パラメータの説明をしますと、valueは変数宣言の文字列、conditionsは、testの文字列とformの文字列のタプルのリスト、guardは最終的にどのtestにもパスしなかった場合に返す「もの」、という形になっており、やや制約があります。「もの」としましたのは、ここに関数も入れることが可能だからです。上記のコードに少し追加して、数字として表示される値をHelloに変えて表示するということも可能です。

def hello():
    return "Hello"

for i in range(16):
    print(cond(f"x = {i}", [
        ("x % 15 == 0", "FizzBuzz"),
        ("x % 5 == 0", "Buzz"),
        ("x % 3 == 0", "Fizz")
        ],
        hello()
        ))
結果は以下のようになります。

$ python cond.py
FizzBuzz
Hello
Hello
Fizz
Hello
Buzz
Fizz
Hello
Hello
Fizz
Buzz
Hello
Fizz
Hello
Hello
FizzBuzz

しかしながら、もう少しいい感じに使い勝手がよいものを作成したいものです。