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

みなさん、こんにちは。
[if \_\_name\_\_ == '\_\_main\_\_' の下にコードをダラダラと書く人、挙手しなさい](http://qiita.com/pashango2/items/57d8a08e53a4548fb5ad)が「いいね」100を超えました、ありがとうございます。
先生、みんなに話しておきたい事があります。

# Shadows name の恐ろしさ

みなさん、`Shadows name`警告を甘く見過ぎです。
グローバルスコープを汚染することによって引き起こされる`Shadows name`の恐ろしさを説明しましょう。

テキトウな例で申し訳ありませんが、以下のコードがあったとします。

```python
import sys

def process(n):
    x = 0

    # ...なんかいろんな処理

    if x > 1:
        n *= 10

    # ...なんかいろんな処理

    return n


if __name__ == '__main__':
    for x in sys.argv[1:] or [1, 2, 3]:
        process(int(x))
```

ある事情により、process関数の始め方の処理が不要になりましたので、変数`x`をコメントアウトしました。
しかし中盤のコードに埋まっていた変数`x`を見落としてしまいました。

```python
def process(n):
    # ここをコメントアウト
    # x = 0

    # ...なんかいろんな処理

    # !!!! コメントアウトしわすれた !!!!
    if x > 1:
        n *= 10

    # ...なんかいろんな処理

    return n
```

この場合、`x`がグローバル変数として参照されるのでエラーになりませんし、静的解析ツールにも検知されません。

Pythonにおける単純なミスは99%静的解析で検知できますが、`Shadows name`はそれをすり抜けてしまう厄介なバグになります。
静的解析をすり抜けてしまうということは、コメントアウト１つするにも細心の注意を払う必要があります。

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

もちろん、先ほどの例は極端なシチュエーションでしたが、起こる可能性は充分にあります。
こんな厄介なバグを引き起こすリスクを抱えるくらいならば、`if __name__ == '__main__'`の下は早々に関数で包んでしまった方が気が楽ですよね。


### <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> PyCharm先生の注意を無視してはいけません(追記)

実際の話、PyCharmのようにリアルタイムで静的解析してくれるツールでは、コードを書く途中で注意してくれるので、この問題はあまり起こらないかもしれません。

![2017-03-10_13h07_48.png](https://qiita-image-store.s3.amazonaws.com/0/140075/cf9ac849-652b-cac9-43cd-c765670fa27f.png)

しかし警告を無視していたりOFFにしていると、こうなります。
沈黙するPyCharm先生...

![2017-03-10_13h08_07.png](https://qiita-image-store.s3.amazonaws.com/0/140075/04a63267-b624-c842-0005-38a1f09641e7.png)

Pythonの静的解析ツールは、時にわかりにくいバグも未然に防いでくれます。
その警告を埋もれさせないよう、コードの状態を常にグリーンにするよう心がけることが大切です。


# if \_\_name\_\_ == '\_\_main\_\_'を書かないという人へ

そもそも`if __name__ == '__main__'`は、トップレベルのスクリプト環境の場合のみ実行したい処理を書く場所です。

では、トップレベルのスクリプトとは何かというと、Pythonから直接実行される**"メインモジュール"**の事です。
メインモジュール、または他のスクリプトからimportされるスクリプトを単に**"モジュール"**と呼びます。

https://docs.python.jp/3/tutorial/modules.html

メインモジュールとしてしか実行されないスクリプトには、基本的に`if __name__ == '__main__`は必要はありません。だって`__name__`には絶対に`__main__`しか入らないのですから、if文を書くだけ無駄ですよね。

**「じゃあ、メインモジュールに`if __name__ == '__main__`なんか書かなくていいんじゃん」**

と、なりますよね。

先生の意見は**「メインモジュールにそれなりのコードを書くのであれば、`if __name__ == '__main__`を書くべき」**です。

例えば、以下のようなメインモジュールがあったとします。

```python
import sys


def main(args=sys.argv):
    # なんちゃらかんちゃら

    return 0

if __name__ == "__main__":  
    sys.exit(main())
```

典型的なメインモジュールの処理です。
`if __name__ == '__main__`がないメインモジュールは以下のようになります。

```python
import sys


def main(args=sys.argv):
    # なんちゃらかんちゃら

    return 0


sys.exit(main())
```

この２つは同じ処理をしますが、2つ目のメインモジュールは困ることが１つだけあります。

**他の人がモンキーパッチができない**

ということです。

# モンキーパッチとは？

モンキーパッチとは既存のライブラリの動作を乗っ取って、動的に書き換えてしまうテクニックです。

[モンキーパッチ Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%82%AD%E3%83%BC%E3%83%91%E3%83%83%E3%83%81)

モンキーパッチの実例は、先生の記事を参照してください。

[Sphinxのドキュメント作成を便利にする「sphinx-quickstart-plus」を作りました](http://qiita.com/pashango2/items/512e567b328058d4107a)

つまり、あなたが作ったスクリプトを他の誰かが拡張したいときに、`if __name__ == '__main__`がないと、モンキーパッチがしにくいコードになります。

以下のような`a.py`というメインモジュールがあったとしましよう。

```python:a.py
import sys


def main(args=sys.argv):
    # なんちゃらかんちゃら

    return 0


sys.exit(main())
```

この`a.main`関数をモンキーパッチ（拡張）しようとしてインポートすると、プログラムが終了してしまいます。

```python:monkey.py
import a

print("monkey patch")
    
a.main([])
```

ですので、メインモジュールでも`if __name__ == '__main__`を書いておいた方が無難（必須ではない）です。
ただし、サンプルコードや書捨てコードであれば`if __name__ == '__main__`は不要です。


# まとめ

先生の言いたいことは、この２つです。

- グローバルスコープを汚すことは静的解析の信頼性を落とす行為、ギルティ！
- メインモジュールでも`if __name__ == '__main__`を書いたほうが無難

以上です。