2021年2月23日火曜日

Pythonの三項演算子は気持ち悪い

三項演算子の話である.簡単な例題として,2つの引数のうち大きいほうを返す関数max(a, b)を考えよう.

CやRubyなどの場合

まずは基準としてCで三項演算子を使った実装を考える.データ型は便宜上intとしよう.

int max(int a, int b) {

  return (a > b) ? a : b;

}

まあ,こんな感じかな? 

Rubyだとこんな感じになる.

def max(a, b)

  return (a > b) ? a : b

end

RubyにもCと同じ三項演算子が用意されているので,こんな形で書ける.動的型付け言語なのでデータ型が陽には出てこない点に注意されたい.

そして,JavaScriptだとこんなに簡潔に書ける.ワンライナーだ.JavaScriptも型はいらない.

max = (a, b) => (a > b) ? a : b

実はRubyだと次のようにも書ける.if文自体が値を持つので,少し気持ち悪いがこんな書き方ができる.

def max(a, b)

  return (if (a > b) then a else b end)

end

return文の次の,if文全体を括るカッコは必須である.このカッコがないと文法エラーになる.

Pythonの場合

さてPythonである.Pythonにも三項演算子があることはある.ただし,ここで示したような形ではない.Pythonで三項演算子を用いて同様の関数を定義すると,次のようなものとなる.

def max(a, b):

  return a if (a > b) else b

ああ,なんてこったぃ!/(^o^)\

Pythonの三項演算子は,「(Trueの値)if (条件式)else(Falseの値)」という実に気持ちの悪いフォーマットで定義されているのだ.

いわゆる後置の条件式と考えると,Rubyでも似たような書き方をすることができる.こんな感じで.

def max(a, b)

  return a if (a > b); b

end

ただし,Rubyにおける後置のif文でelse節は書けないので,この場合はたまたまそこでreturnしてしまうことを利用して,elseに相当する処理を次の文として書くことで類似のコードにしているのである.そして,関数の最後にreturn文を明示しなくても最後に評価した値を返すという性質を利用して,なんとなくそれっぽく書いているだけなのである(※).

しかし,これは出口が2つになってしまうため,厳密には構造化プログラミングの定義から外れてしまう問題が生じている.なによりトリッキーな書き方であり,バグの温床となりそうなこんな書き方をしてはいけない.

というわけで結論

Pythonの三項演算子は気持ち悪い.

※の説明

def max(a, b)

  return a if (a > b); b

end

このコードは次のコードと同じである.

def max(a, b)

  return a if (a > b)

  b

end

そして,このコードはさらに次のコードと同じである.Pythonの三項演算子と似ているが全く違うことを理解できるだろう.

def max(a, b)

  return a if (a > b)

  return b

end


0 件のコメント:

コメントを投稿