あまり良くない書き方 その2 関数外の長い処理

ある程度プログラムを書ける人であればプログラムの規模に応じて適切な単位で関数、クラス、モジュールを分割しますが、そんな人でも分析バッチや移行バッチのように使い捨てでプログラムを作成する場合、ついつい長い処理の塊のスクリプトを書いてしまうことがあるのではないでしょうか?

さて、今回もクイズからです。以下のスクリプトは正常に動きますが、どんな危険性をはらんでいるでしょうか?

def add100(arg):
    """ 引数に対して100加算する """
    x = 100 
    return arg + x 

if __name__ == '__main__':
    x = 1 
    y = 2 
    z = x + y 
    w = add100(z)
    print(w)

if __name__ == '__main__':の下で変数を定義していますが、これは関数の外なのでグローバルスコープに属しています。(グローバル変数についてはglobal宣言を参照してください)。

さらに関数add100内、3行目でもxという変数が定義されています。4行目return arg + xで書かれているxはローカル変数のxなのですが、7行目のグローバル変数と同じ名前になっていますね。

さて、何らかの機能修正で3行目を削除すると、4行目のxは未定義なので実行時にエラーが出てくれそうなものなのですが、ローカルスコープに変数がない場合は自動的にグローバルの変数を参照するためエラーが発生せずに不具合に気づかない危険性があります。

ですので、if __name__ == '__main__':の下にはmain関数のみ記述するようにしたほうがよいでしょう。

def add100(arg):
    x = 100
    return arg + x

def main():
    x = 1 
    y = 2
    z = x + y
    w = add100(z)
    print(w)

if __name__ == '__main__':
    main()

前回の内容とも少しかぶるのですが、pythonである程度長いコードを書いていて不思議な挙動をする場合(あくまでもわたしの経験上ですが)変数の汚染が原因となっていたことが、ある一定の割合で起きていました。前回のものは(完全な)グローバルなオブジェクト、今回のサンプルはモジュール内でのグローバル変数に関するものをご紹介しました。