普段 Python:Ruby = 7:3 くらいの比率で書いていると,些細だけど大きな両者の違いに気がつく(と同時に,あーやっぱ Ruby っていいなって思う)ことが結構あって,
例えば(連想)配列アクセスで,範囲外のインデクスやらキーを指定した場合,
- Python -> 例外(IndexError/KeyError)を投げる
- Ruby -> nil を返す
という決定的な違いがある.
いちいち例外を投げられると,それを適切にハンドリングしてあげないといけないのはちょっと面倒だったりする.
本当に卑近な例だけど,設定ファイルを yaml で読み込んで,連想配列に変換して,その要素にアクセスするなんて場面を考えてみる.たとえば,
foo: 100
bar: 200
hoge: 300
みたいな YAML があったとして,適当なライブラリを使って,連想配列にできるけど,実は設定ファイルにはバリエーションがあって,
foo: 100
bar: 200
みたいに,一部のプロパティは欠けている場合もある.そんなときに,デフォルト値決めたいなーってってとき.
Ruby なら,(連想配列にキーがなければ nil を返してくれるので.しかも || が式なので)
hoge = setting[:hoge] || 500
と書ける.最初見たときは相当抵抗があったけど,まぁ慣れれば.
一方 Python では,
if not "hoge" in setting.keys():
hoge = 500
とか
try:
hoge = setting["hoge"]
except IndexError:
hoge = 500
みたいなことを書く必要があって,ネストが少なくとも1段深くなる.と思ったので,前置きが長くなったけど,下のように書けば,とりあえずは解決できる.
def safe_get(obj, default):
try:
return obj()
except:
return default
使い方は
a = range(10)
safe_get(lambda: a[5]) #=> 6
safe_get(lambda: a[100], 1234) #=> 1234
lambda にくるんであげることで,例外の発生もsafe_get
の中に閉じ込めることができるので,関数内で例外のハンドリングができるようになる.
この手法がなかなか技巧的でかっこいいんじゃないかと思ったけど,もっとうまい解決方法が多分あるんだろうなとも思うわけですが,どうなんでしょうか?