modalsoul’s blog

これは“失敗”と呼べるかもしれないが、ぼくは“学習体験”と呼びたい

Pythonのand, orやallの挙動が正格に見えたけど、ちゃんと非正格だった話

会社のSlackでの1コマ


Pythonorallで、式の評価を途中でやめてくれない

>>> print('a') or pring('b')
a
b

↑の場合、直感的にはbは出力されないはずだけど、バッチリでてる

Pythonって正格なのか、、?と思うも、

>>> 0 and print('b')
0

こっちだとorは非正格に見える

この差異はprintの返り値がNoneのために起きてる

Noneの真偽値は、False

>>> bool(None)
False

なので、↑のケースでprintの結果にTrueを期待してると、裏切られると言う訳


次にall

printFalseに評価されることを踏まえて、

def a():
  print('a')
  return True

def b():
  print('b')
  return False

def c():
  print('c')
  return True

とすると

result = all([a(), b(), c()])
print(result)

result2 = (a() and b() and c())
print(result2)

a
b
c
False
a
b
False

という結果になる

andは非正格だけど、all正格に見えてしまう


これにもタネがあって、↑のa,b,call実行時ではなく、リスト生成時に出力されているから

>>> [a(), b(), c()]
a
b
c
[True, False, True]

こんな感じ

なので、改めてallを検証すると

class A:
  def __bool__(self):
    print('a')
    return True

a = A()

とすると、

>>> all([True, a, False, a])
a
False

となって、allは非正格なことが確認できた