21
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

例外は時として

Posted at

普段 Python:Ruby = 7:3 くらいの比率で書いていると,些細だけど大きな両者の違いに気がつく(と同時に,あーやっぱ Ruby っていいなって思う)ことが結構あって,
例えば(連想)配列アクセスで,範囲外のインデクスやらキーを指定した場合,

  • Python -> 例外(IndexError/KeyError)を投げる
  • Ruby -> nil を返す

という決定的な違いがある.

いちいち例外を投げられると,それを適切にハンドリングしてあげないといけないのはちょっと面倒だったりする.

本当に卑近な例だけど,設定ファイルを yaml で読み込んで,連想配列に変換して,その要素にアクセスするなんて場面を考えてみる.たとえば,

setting.yml
foo: 100
bar: 200
hoge: 300

みたいな YAML があったとして,適当なライブラリを使って,連想配列にできるけど,実は設定ファイルにはバリエーションがあって,

setting.yml
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の中に閉じ込めることができるので,関数内で例外のハンドリングができるようになる.
この手法がなかなか技巧的でかっこいいんじゃないかと思ったけど,もっとうまい解決方法が多分あるんだろうなとも思うわけですが,どうなんでしょうか?

21
20
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?