えせはらさん( @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 コメント:
コメントを投稿