みなさん、こんにちは。
if __name__ == '__main__' の下にコードをダラダラと書く人、挙手しなさいが「いいね」100を超えました、ありがとうございます。
先生、みんなに話しておきたい事があります。
Shadows name の恐ろしさ
みなさん、Shadows name
警告を甘く見過ぎです。
グローバルスコープを汚染することによって引き起こされるShadows name
の恐ろしさを説明しましょう。
テキトウな例で申し訳ありませんが、以下のコードがあったとします。
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
を見落としてしまいました。
def process(n):
# ここをコメントアウト
# x = 0
# ...なんかいろんな処理
# !!!! コメントアウトしわすれた !!!!
if x > 1:
n *= 10
# ...なんかいろんな処理
return n
この場合、x
がグローバル変数として参照されるのでエラーになりませんし、静的解析ツールにも検知されません。
Pythonにおける単純なミスは99%静的解析で検知できますが、Shadows name
はそれをすり抜けてしまう厄介なバグになります。
静的解析をすり抜けてしまうということは、コメントアウト1つするにも細心の注意を払う必要があります。
そこ、Python先生の言語仕様をディスるのはやめなさい。
もちろん、先ほどの例は極端なシチュエーションでしたが、起こる可能性は充分にあります。
こんな厄介なバグを引き起こすリスクを抱えるくらいならば、if __name__ == '__main__'
の下は早々に関数で包んでしまった方が気が楽ですよね。
PyCharm先生の注意を無視してはいけません(追記)
実際の話、PyCharmのようにリアルタイムで静的解析してくれるツールでは、コードを書く途中で注意してくれるので、この問題はあまり起こらないかもしれません。
しかし警告を無視していたりOFFにしていると、こうなります。
沈黙するPyCharm先生...
Pythonの静的解析ツールは、時にわかりにくいバグも未然に防いでくれます。
その警告を埋もれさせないよう、コードの状態を常にグリーンにするよう心がけることが大切です。
if __name__ == '__main__'を書かないという人へ
そもそもif __name__ == '__main__'
は、トップレベルのスクリプト環境の場合のみ実行したい処理を書く場所です。
では、トップレベルのスクリプトとは何かというと、Pythonから直接実行される**"メインモジュール"の事です。
メインモジュール、または他のスクリプトからimportされるスクリプトを単に"モジュール"**と呼びます。
メインモジュールとしてしか実行されないスクリプトには、基本的にif __name__ == '__main__
は必要はありません。だって__name__
には絶対に__main__
しか入らないのですから、if文を書くだけ無駄ですよね。
「じゃあ、メインモジュールにif __name__ == '__main__
なんか書かなくていいんじゃん」
と、なりますよね。
先生の意見は**「メインモジュールにそれなりのコードを書くのであれば、if __name__ == '__main__
を書くべき」**です。
例えば、以下のようなメインモジュールがあったとします。
import sys
def main(args=sys.argv):
# なんちゃらかんちゃら
return 0
if __name__ == "__main__":
sys.exit(main())
典型的なメインモジュールの処理です。
if __name__ == '__main__
がないメインモジュールは以下のようになります。
import sys
def main(args=sys.argv):
# なんちゃらかんちゃら
return 0
sys.exit(main())
この2つは同じ処理をしますが、2つ目のメインモジュールは困ることが1つだけあります。
他の人がモンキーパッチができない
ということです。
モンキーパッチとは?
モンキーパッチとは既存のライブラリの動作を乗っ取って、動的に書き換えてしまうテクニックです。
モンキーパッチの実例は、先生の記事を参照してください。
Sphinxのドキュメント作成を便利にする「sphinx-quickstart-plus」を作りました
つまり、あなたが作ったスクリプトを他の誰かが拡張したいときに、if __name__ == '__main__
がないと、モンキーパッチがしにくいコードになります。
以下のようなa.py
というメインモジュールがあったとしましよう。
import sys
def main(args=sys.argv):
# なんちゃらかんちゃら
return 0
sys.exit(main())
このa.main
関数をモンキーパッチ(拡張)しようとしてインポートすると、プログラムが終了してしまいます。
import a
print("monkey patch")
a.main([])
ですので、メインモジュールでもif __name__ == '__main__
を書いておいた方が無難(必須ではない)です。
ただし、サンプルコードや書捨てコードであればif __name__ == '__main__
は不要です。
まとめ
先生の言いたいことは、この2つです。
- グローバルスコープを汚すことは静的解析の信頼性を落とす行為、ギルティ!
- メインモジュールでも
if __name__ == '__main__
を書いたほうが無難
以上です。