1. Qiita
  2. 投稿
  3. Python

if __name__ == '__main__' の下にコードをダラダラと書く人、挙手しなさい

  • 11
    いいね
  • 2
    コメント

あけましておめでとうございます。
新年早々ですが、先生、みなさんに言いたいことがあります。

pythonコードで、if __name__ == '__main__'の下にコードをダラダラと書く人、挙手しなさい。

こんな感じに、if __name__ == '__main__'の下にコードを書く人です。

#! usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function, absolute_import
import sys


def say_args(kind, data_list):
    print("kind:", kind, " data:", data_list)


if __name__ == '__main__':
    args = sys.argv[1:]
    assert args

    kind = args[0].lower()
    data_list = [x.lower() for x in args[1:]]

    say_args(kind, data_list)

こういうコードを書いている人、先生、怒らないから挙手しなさい。

こういうコードはグローバルスコープの名前空間を汚染しているという事に気付いていますか?
気付いており理解した上で書いているという人、手を下ろして結構です。

if __name__ == '__main__'下はグローバルスコープ

そうです、if __name__ == '__main__'下はグローバルスコープです。
そこで定義された変数は、すべてグローバル変数になるということです。

先ほどのコードではローカル変数のつもりのargs, kind, data_list、はては一時変数のxまでもグローバル変数なってしまうのです。
ですので、以下のようなコードを書いてもエラーにはなりません。

def say_args(kind, data_list):
    print("kind:", kind, " data:", data_list)
    # 未定義のxを参照してもエラーにならない、グローバル変数xが参照される
    print("x: ", x)

これは直接実行するとエラーにならず、モジュールとして呼ぶとAttribute Errorになるという、やっかいなバグの元になります。

そこ、python先生の言語仕様をディスるのはやめなさい。

この件についてはPyCharm先生も「Shadows name 'kind' form outer scope」とお怒りです。

2017-01-01_11h04_25.png

解決方法

if __name__ == '__main__'下でコードを書きたい場合は、関数でくるみましょう。

#! usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function, absolute_import
import sys


def main(args):
    assert args

    kind = args[0].lower()
    data_list = [x.lower() for x in args[1:]]

    say_args(kind, data_list)


def say_args(kind, data_list):
    print("kind:", kind, " data:", data_list)


if __name__ == '__main__':
    main(sys.argv[1:])

main関数でくるむことによってグローバルスコープの名前空間は汚染されません。またmain関数でくるむことにより、main処理を冒頭に書けるのでコードの見通しがよくなります。

python初心者のみなさんは関数でくるんでおいた方が無難です。

他にもいろいろ心配という方はPyCharm先生を使ってください、それはもう小姑のように・・いえ、手取り足取りコードのダメな所を指摘してくれます。
pyflask先生 pyflakes先生やpylint先生でもかまいません、pylint先生の方が厳しめです。
(1/1 修正:pyflask先生はいません、pyflakes先生の間違いでした)

先生の言いたかったことは以上です。

それから「main関数でくるんだら、モジュールとして使いたい時に無駄なmain関数ができるじゃん」という人、後で職員室で先生と個別に話し合いましょう。