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

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

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

こんな感じに、if \_\_name\_\_ == '\_\_main\_\_'の下にコードを書く人です。

```python
#! 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```、がグローバル変数になってしまうのです。
ですので、以下のようなコードを書いてもエラーにはなりません。

```python
def say_args(kind, data_list):
    print("kind:", kind, " data:", data_list)
    # 未定義のargsを参照してもエラーにならない、グローバル変数argsが参照される
    print("args: ", args)
```
※上記の一文は修正しています、詳しくは[「2017-01-02 変数「x」について訂正」](http://qiita.com/pashango2/items/57d8a08e53a4548fb5ad#2017-01-02-%E5%A4%89%E6%95%B0x%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%A8%82%E6%AD%A3)をご覧ください。

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

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

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

<img width="289" alt="2017-01-01_11h04_25.png" src="https://qiita-image-store.s3.amazonaws.com/0/140075/339f1ce8-f8ab-ff6e-8fc0-8afcdc820bde.png">

## 解決方法
if \_\_name\_\_ == '\_\_main\_\_'下でコードを書きたい場合は、関数でくるみましょう。

```python
#! 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関数ができるじゃん」という人、後で職員室で先生と個別に話し合いましょう。

### 補講を書きました

[【補講】if \_\_name\_\_ == '\_\_main\_\_' の下にコードをダラダラと書く人、挙手しなさい](http://qiita.com/pashango2/items/3834221353e4d25e0d69)


## 2017-01-02 変数「x」について訂正

knoguchiさんのコメントを受けまして、訂正いたします。
記事中に訂正を入れると記事が読みにくくなりますので、文末に移動しています。

**[訂正前の文章]**
先ほどのコードではローカル変数のつもりの```args```, ```kind```, ```data_list```、~~一時変数の```x```までも~~グローバル変数なってしまうのです。

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

内包表記内で使用された```x```についてはグローバル変数にはなりません、エラーになります。

ただし、PyCharmの実行上はエラーにならないようです、これはPyCharmが高速化のためにグローバルフレームを再利用しているためです。
結果の確認はPyCharm上の実行だけではいけないという事ですね、教訓になりました。

改めてknoguchiさんにお礼を申し上げます。
コメント中の「リストコンプリヘンションの変数リークは再束縛の問題」は内包表記でハマりポイントの1つであるので、コメントも併せてご覧ください。