スクリプトファイルのモジュール化

 ちょっと復習。今までルーチンワークをまとめるということで、ルーチンワークを単純に並べた関数、メゾットとアトリビュートという形でまとめたクラスについて説明してきました。今度はスクリプトファイルをひとまとめにして、他のスクリプトファイルから使ってみるところを説明します。まずは例としてなんてことはないファイル("mymodule.py")を作ります。

# coding: shift-jis

# 変数を定義します。
a = '実験です'
b = 3

#関数を定義します。
def cubic():
  print '変数bの3乗は',b*b*b,'です。'

class Animal(object):
  def __init__(self, name, nakigoe):
    self.name = name
    self.nakigoe = nakigoe

  def naku(self):
    print self.name + "が「" + self.nakigoe + "」と鳴きました。"

print 'これからテストをしてみます。'

if __name__ == '__main__': ←新しい内容です。ここがポイント!
  print '変数aの中身は"',a,'"という文字列です。'
  b=5
  cubic()
  cat = Animal("猫","ニャーニャー")
  cat.naku()
  raw_input()

 if __name__ == '__main__':
 なんてことないと言いつつ、知らない内容ですね。済みません。後で説明します。まずは出力画面を見てください。次のようになっているはずです。
出力画面:
 これからテストをしてみます。
 変数aの中身は" 実験です "という文字列です。
 変数bの3乗は 125 です。
 猫が「ニャーニャー」と鳴きました。
※このファイルをファイル名"mymodule.py"にして、ironpythonのフォルダ(ipy.exeのあるフォルダ)の"Lib"のフォルダの中に保存します。

 スクリプトファイルをモジュールとして取り込む

 まずインタプリタシェルを立ち上げて、次のコマンドを入力してみてください。


 >>> dir()
 ['__builtins__', '__doc__', '__name__'] 

 >>> var = 1234 ←"var"という変数を定義します。

 >>> dir()
 ['__builtins__', '__doc__', '__name__', 'var'] ←"var"が追加された

 この"dir()"関数は定義されている名前をみることができます。なので新しく変数を定義すれば、追加されていることが確認できます。それでは先程作った"mymodule.py"を取り込んでみましょう。


 >>> import mymodule ←拡張子を抜いたファイル名で呼び出します。
 これからテストをしてみます。 ←"mymodule.py"内のコマンドが実行されました。

 >>> dir()
 ['__builtins__', '__doc__', '__name__', 'mymodule', 'var']

 >>> dir(mymodule) ←mymoduleの中を覗いてみましょう。
 ['Animal', '__builtins__', '__file__', '__name__', 'a', 'b', 'cubic']

 >>> dir(mymodule.Animal) ←Animalクラスの中を覗く。
 ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__',
  '__hash__', '__init__', '__module__', '__new__', '__reduce__',
  '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__',
  'naku']

 >>> __name__
 '__main__' 
 >>> mymodule.__name__
 'mymodule' ←mymodule"__name__"が"__main__"ではない。

モジュールを取り込むコマンド
 import <モジュール名(ファイル名)>

 上記のコマンドを使って"mymodule"を取り込みます。するとdir関数で覗いてみるとmymoduleが追加されていることが分かります。

 dir(モジュール名)
 dir関数を使ってmymodule内で定義させている名前をみることが出来ます。
"Animal"、"a"、"b"、"cubic"が定義されているのが分かります。更にdir(クラス名)でクラス内で定義されている名前を覗くことが出来ます。
 こんな風にdir関数を使っていると、Animalという領域に定義されている名前、mymoduleという領域に定義されている名前を見ている気になりませんか。実はその感じで正しいです。dir関数はそれぞれの領域で定義されている名前を出力する関数です。またIron Pythonでは名前を定義されている領域のことを"名前空間"と呼びます。では何にも引数を書かなかった"dir()"の場合は、一番大きなglobal領域の名前空間の中身を出力していることになります。

 当然globalの名前空間の"__name__"とmymoduleの名前空間の"__name__"の中身が違います。

 gloobalの"__name__" == "__main__"
 mymodulelの"__name__" == "mymodule"

 これを見るとmymodule.pyで記述した"if __name__ == '__main__':"の意味が分かってきませんか。つまりmymodule.pyをスクリプトファイルとして実行するとmymodule == globalになるので__name__は__main__となりインデックスで示されるブロックが実行されます。逆にモジュールとして実行される場合は、__name__は__main__ではないのでブロックは実行されません。"if __name__ == '__main__':"構文は、モジュール化を想定したスクリプトファイルに用いられ、一般にモジュール内のオブジェクトの動作確認に使用されます。

 取り込んだモジュールの使い方は次の通りです

 >>> print mymodule.a
 実験です

 >>> print mymodule.b
 3

 >>> mymodule.cubic()
 変数bの3乗は 27 です。

 >>> mymodule.b = 4 ←変数bを変更する。

 >>> mymodule.cubic()
 変数bの3乗は 64 です。 ←変数bを変更したので結果が変わりました。

 >>> dog = mymodule.Animal('dog', 'bow wow')

 >>> dog.naku()
 dogが「bow wow」と鳴きました。

もう一つのモジュールの取り込み方

 import文の代わりにfrom文を使ってモジュールを取り込むことが出来ます。モジュール名を記述せず、直接関数や変数を利用したいときに便利です。
 使い方は次の通りです。

 from <モジュール名> import <関数名や変数名>

 インタプリタシェルを使って試してみましょう。

 >>> import mymodule 
 これからテストをしてみます。

 >>> from mymodule import Animal
 >>> chikin = Animal('chikin', 'cock-a-doodle-doo')
 >>> chikin.naku()
 chikinが「cock-a-doodle-doo」と鳴きました。

 わざわざ関数名や変数名を入力するのが面倒なときは、次のように省略することも出来ます。

 >>> import mymodule 
 これからテストをしてみます。

 >>> from mymodule import * ←"*"を使うことで全部取り込めます。
 >>> dir()
 ['Animal', '__builtins__', '__doc__', '__name__', 'a', 'b', 'cubic',
 'mymodule']

 >>> print a
 実験です

 >>> print b
 3
 >>> cubic()
 変数bの3乗は 27 です。

 >>> b = 6 ←変数bを変更したのに・・・
 >>> cubic()
 変数bの3乗は 27 です。 ←cubic()の結果が変わりません?

 >>> mymodule.b = 6
 >>> cubic()
 変数bの3乗は 216 です。←cubic()はmymodule.bを参照しています。

 "*"を使うことで全部取り込めます。でも注意が必要です。import文はあくまでfrom文で示されたモジュールの名前空間の内容を、globalの名前空間にコピーしているだけです。
なので、"a"は"mymodule.a"をコピーしたものであって同じものではないのです。
つまり"a"の内容を変更しても"mymodule.a"の内容は変わりません。
 cubic()関数内部もいっしょ。関数内部ではmymodule.bを参照しているので、globalの名前空間にコピーされた"b"を変更しても何も影響されません。

スクリプトファイル内でモジュールを取り込む

 インタプリタシェルを使って説明したことをスクリプトファイルで書いてみましょう。
 今度はmymodule.pyと下記スクリプトファイルを同じフォルダに入れます。

# coding: shift-jis

import mymodule
from mymodule import *

print a
print b
cubic()
b = 2
cubic()
mymodule.b = 8
cubic()
chikin = Animal('鶏','コケコッコー')
chikin.naku()

raw_input()

出力画面:
 これからテストをしてみます。
 実験です
 3
 変数bの3乗は 27 です。
 変数bの3乗は 27 です。
 変数bの3乗は 512 です。
 鶏が「コケコッコー」と鳴きました。
 インタプリタシェルでやったことの復習なので説明はいらないでしょう。