えせはらさん( @esehara )のブログ(蟲!虫!蟲! - #!/usr/bin/bugrammer)の以下の投稿を読んで。
変数に代入せず、関数でandやorで判定しているときに気をつけたいこと
その関数、メソッドは他に副作用を持つか?または副作用を持ったあとに、何かしら値を使う必要があるか?
ということに注意しないといけない。もし、上記に当てはまる場合は、真偽値を一度変数に代入して持っておき、あとでそれをandやorによって比較したほうが安全だと思う。
よく使うなら、その都度変数に代入してその変数を使う(2回書く必要がある)のも大変だし、あれば便利かなぁと思ってショートサーキット評価(短絡評価)を避けるための関数(ロングサーキット評価?)を書いてみた。
コード(BBEdit)
sample.py
#!/usr/bin/env python3.3 #-*- coding: utf-8 -*- def longCirEval4Func(*funcs, op="and"): op = op.lower() bools = [func() for func in funcs] if op == "and": for b in bools: if not b: return False else: return True elif op == "or": for b in bools: if b: return True else: return False raise Exception("error: op should be 'and' or 'or'") class Foobar(object): def __init__(self, numbers): self.numbers = numbers def has_odd(self): odd = [] has_odd = False for number in self.numbers: if number % 2 == 1: odd.append(number) has_odd = True self.odd = odd return has_odd foo = Foobar([1, 3, 5, 9]) bar = Foobar([2, 4]) foobar = Foobar([1, 2, 4]) print("and/or演算子の前に関数を呼び出す場合") tmp1, tmp2, tmp3 = foo.has_odd(), bar.has_odd(), foobar.has_odd() if tmp1 and tmp2 and tmp3: print("ALL ODD") for x in [foo, bar, foobar]: print(x.odd) foo = Foobar([1, 3, 5, 9]) bar = Foobar([2, 4]) foobar = Foobar([1, 2, 4]) print("longCirEval4Funcを使った場合") if longCirEval4Func(foo.has_odd, bar.has_odd, foobar.has_odd, op="and"): print("ALL ODD") for x in [foo, bar, foobar]: print(x.odd)
副作用がちゃんと起こっているかどうか確認。
入出力結果(Terminal)
$ ./tmp.py and/or演算子の前に関数を呼び出す場合 [1, 3, 5, 9] [] [1] longCirEval4Funcを使った場合 [1, 3, 5, 9] [] [1] $
foobar.oddが作成されているのが確認できた。
けど、せっかく作成してはみたものの、必ず実行させたい関数、副作用を起こしたい関数、メソッドが特に多い場合以外は、変数に代入する方法で十分かも。。><w
他にもbool演算の応用などについて詳しくは、『初めてのPython 第3版』のp.264とかに記述有り。
0 コメント:
コメントを投稿