【Python】よくわからん「or」の使い方
きっかけはx = x or []
GitHubの他人のコードで見たときに、「ん?」と口に出た。
1年ほどPythonに触れながら、今までに見たことがなかった使い方だったので焦るわし。
今回はor
の変わった使い方と、使い時、良し悪しについて考えてみます!
結論
使わない。
動くけど、意味がわかりづらいので使わないほうが良いと「私は」思います。
より良いとされるif foo is None:
といった判定法が推奨されているようです。
具体例
サンプルコード
def append_num(num, group): group = group or [] group.append(num) return group if __name__ == "__main__": group1 = [1, 2, 3] group2 = None print("Before: {}, {}".format(group1, group2)) group1 = append_num(100, group1) group2 = append_num(100, group2) print("After: {}, {}".format(group1, group2))
実行結果
Before: [1, 2, 3], None After: [1, 2, 3, 100], [100]
or []
の意味としては、「左がNoneのとき、右を実行する」という認識でいいのでしょうか…
group2
はもともとNoneだったので、関数内で空のリストに置き換わります。
もしor []
がなかった場合以下のような実行結果になります。
Before: [1, 2, 3], None Traceback (most recent call last): File "main.py", line 104, in <module> group2 = append_num(100, group2) File "main.py", line 76, in append_num group.append(num) AttributeError: 'NoneType' object has no attribute 'append'
なので、None
によるエラーを回避する手段として利用している方もいるようですね。
ただGoogle Style Guideを確認したところ、以下のような記述がありました。
Always use
if foo is None:
(oris not None
) to check for a None value-e.g., when testing whether a variable or argument that defaults to None was set to some other value. The other value might be a value that’s false in a boolean context!
Noneかどうかの判定にはif foo is None
を使え、Falseを示す値はいくつかあるぞ!って感じでしょうか(笑)
試してみたところ、このor
は当然かも知れませんがNoneだけでなくFalseのときも同様に動きます。
group2
の初期値を0
に変更
if __name__ == "__main__": group1 = [1, 2, 3] group2 = 0 # initialize 0 print("Before: {}, {}".format(group1, group2)) group1 = append_num(100, group1) group2 = append_num(100, group2) print("After: {}, {}".format(group1, group2))
実行結果
Before: [1, 2, 3], 0 After: [1, 2, 3, 100], [100]
よってNoneによる誤作動を防ぐことはできますが、None以外のFalseになる値(0, [], {}, ())を入れてしまっても動いてしまうプログラムの完成です。あかんですね。
なのでGoogle Style Guideでは以下の記述が推奨されていました。
# BAD def append_num(num, group): group = group or [] group.append(num) return group # GOOD def append_num(num, group): if group is None: group = [] group.append(num) return group
結論・まとめ
結果としては、Googleさんも非推奨ですし使わないようにしようと思うます。
あまり直感的にわからない方が自分も含めいらっしゃると思うので、Python大好き人間の集まりみたいなところでない限りは控えたほうが良いというのが率直な感想です…
ちなみに関数の仮引数に空リストを渡すのはエラーのもとなので非推奨だそうな。
def append_num(num, group=[]): group.append(num) return group if __name__ == "__main__": a = append_num(10) a.append(20) print(a) b = append_num(30) b.append(40) print(b)
実行結果
[10, 20] [10, 20, 30, 40]
2つのリストに分けて初期化していると思いきや、a
とb
は繋がっているようです。Pythonは参照渡しという噂を聞いたことがあります(間違っていたらすいません、コメント頂けると助かります)が、仮引数の[]
によって作成されたリストの参照をa
とb
の両方に渡しているため起こるエラーだそうですよ。
or
の意外な使い方を説明して燃え尽きてしまいました、and
については実際にやってみてください。私は解説をかけるほどうまい解釈を思いつかなかったので、コメントにand
について残して頂ける方がいらっしゃいましたら、末代まで感謝しますので宜しくおねがいします。