リニューアルしました
実はまだ考えていた「Pythonでcond」今回のcondは以下のようなものになりました。
from typing import List
import operator as op
# Usable as a value of TestForm.checker
CHECKER_DICT = {
"eq": op.eq,
"==": op.eq,
"ne": op.ne,
"!=": op.ne,
"<=": op.le,
">=": op.ge,
"<": op.lt,
">": op.gt,
"is": op.is_,
"not": op.is_not
}
class TestForm:
def __init__(self, checker, lhs, rhs, after):
""" Create test-form
:param checker: CHECKER_DICT keys
e.g.) '==', '<=', 'is' etc...
:param lhs: Left hand side
:param rhs: Right hand side
:param after: Processing performed when the result is True.
"""
self.checker = checker
self.lhs = lhs
self.rhs = rhs
self.after = after
class TestFormError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
def cond(conditions: List[TestForm]):
"""
e.g.)
fizzbuzz = lambda x: cond([
TestForm('==', x % 15, 0, 'FizzBuzz'),
TestForm('==', x % 5, 0, 'Buzz'),
TestForm('==', x % 3, 0, 'Fizz')
])
for i in range(1, 31):
if fizzbuzz(i) is None:
print(i)
else:
print(fizzbuzz(i))
"""
for c in conditions:
if c.checker in CHECKER_DICT:
if CHECKER_DICT[c.checker](c.lhs, c.rhs) is True:
return c.after
break
else:
raise TestFormError(f"Can't use {c.checker}")
最初TestForm
はcollections.namedtuple
で実装してみたのですが、そうするとtyping
での型アノテーションの部分で、List[TestForm]
とはできないので、より明確な型指定ができるクラスに変更しました。と言ってもPythonではガチガチの型指定はできないので、あくまで使い方のヒントみたいなものになります。使う際は
cond
のdocstringにあるように、lambda
を活用する感じになります。上記の場合FizzBuzzを例にしておりますが、例えば以下のようなことも可能です。
>>> from cond import *
>>> def hello():
... return "Hello"
...
>>> cond([
... TestForm("==", hello(), "Hello", "This is hello func."),
... TestForm("==", hello(), "Holle", "This is not hello func"),
... ])
'This is hello func.'
使う上での制約として、TestForm.checker
は予め定めたCHECKER_DICT
の中に含まれるものしか使えないようにしています。もし含まれていないものを使用した場合は、TestFormError
となります。