Python の不思議な else

The Zen of Python

Python のインタプリタで
import this
とすると Python の持つ哲学が表示されます。非常に有名な Python のイースターエッグです。
全文は長いので省略しますが、その中にこのような一説があります。
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you’re Dutch.
(ひとつの―たったひとつの―明確なやり方があるはずだ)
(しかし、そのやり方は貴方の国の文化では、一見分かりにくいかもしれない)
Python は基本的に「この実装はこの方法でしか書けない」という構文になっており、誰が書いてもほぼ同じようなコードになります。
よく言われる所では、 Python には switch 文がありません。if 文で代用可能だからです。
しかしながら、「この方法でしか書けない」というのが、一見すると分かりにくいことがあります。
それが、 else の他の言語では見られない使い方です。

普通の if での else

一般的に、else は次のように if 節で使います。もちろん、 Python も同じです。
例えば、100点満点以外では罵倒してくる家庭教師のプログラムは次のように書けます。
if score == 100:
    print("Excellent!")
else:
    print("You're full of sh*t.")
このようにelseは「その他の場合は」といった意味合いで使います。
が、Python はそれ以外の場所 (=somewhere else) でも else が登場します。

ちょっと変わった try での else

一般的に例外処理は try - catch - finally の3つだと思うのですが、Python はこんな風に書けます。
例えば、kurorekishi.txt というファイルを aaaaaa… という文字列で上書きしてなかったことにするプログラムは次のように書けます。
try:
    f = open('kurorekishi.txt', 'w')
except IOError:
    print('ファイルの操作に失敗しました')
    print('aaaaaaaaaaaaaaaaa')  # 更新できなかったことに耐えられず叫ぶ
else:
    f.write('aaaaaaaaaaaaaaaaa')  # aaaa… で上書き
finally:
    f.close()
この場合、else は「例外が発生しなかった場合」に実行されます。
except に対しての else になります。
一般的に、例外が発生しなかった際後の処理もまとめて try の中に書かれるので、処理が長くなると一体何に try しているのかが分からないコードに出会うことがあります。
この書き方であれば try は本当に例外が発生しうる場所だけ書けるので、見た目がスッキリします。
初見だと分かりにくいのですが、とても便利な書き方だと思います。

もはやよく分からない for での else

Python では for, while 文でも else が使えます。
何を言っているのかよく分からないかもしれないので、サンプルを見てください。
与えられた楽曲リストの中身が全て宇多田ヒカルの楽曲タイトルかをチェックするプログラムになります。
def is_utada_song(song) -> bool:
    # 中身は省略...

songs = ['Can You Keep A Secret?', 'Beautiful World', 'Traveling', 'First Love', 'Flavor of Love', 'Love, Day After Tomorrow']

for song in songs:
    if not is_utada_song(song):
        print('{song}は宇多田ヒカルの楽曲ではありません'.format(song=song))
        break
else:
    print('全て宇多田ヒカルの楽曲です')
この場合、elseは「breakしなかった場合」に実行されます。
フラグを使ったりしないと書けないものがスッキリ書けるので、見た目としてシンプルになります。
が、try と違って初見で何をしているか推測するのはちょっと厳しい気がします。
実際、Effective Pythonでも「forとwhileループの後の elseブロックは使うのを避ける」とハッキリ書かれていたり、避けられることもある構文のようです。(この本も賛否両論ある、癖のある本なのですが…)
Python 勉強したての時はドヤァのために何度か使いましたが、最近は使わなくなってしまいました。
もし使うとしたら、 continue と組み合わせて二重 for 文を一気に抜けるときくらいでしょうか?

おわりに

Python は割と他の言語の標準的な書き方を取り入れていると思うのですが、それでもこのような癖のある書き方は存在します。
使うと便利ではあるのですが可読性が落ちてしまう、諸刃の剣だと思っています。

コメント