[Python] os.pathモジュールが使えるようになるまで
環境
この記事の内容は、Ubuntu Linux 6.10, Python 2.4.4c1で確認しました。
疑問点
例えば、以下のようなファイル構造があったとします。
. `-- foo |-- __init__.py `-- bar.py
このうち、foo/__init__.pyは空です。foo/bar.pyは、以下のようになっています。
def baz(): print "baz"
このとき、fooパッケージをimportしただけでは、barモジュールにはアクセスできません。barモジュールにアクセス(し、その中の関数を使用)するためには、foo.barをimportする必要があります。
>>> import foo >>> foo.bar Traceback (most recent call last): File "<stdin>", line 1, in ? AttributeError: 'module' object has no attribute 'bar' >>> import foo.bar >>> foo.bar <module 'foo.bar' from 'foo/bar.pyc'> >>> foo.bar.baz() baz
ところが、os.pathモジュールは、osモジュールをimportした時点で使用できるようになります。もちろん、os.pathモジュール内の関数も使用可能になります。
>>> import os >>> os.path.curdir '.'
これを疑問に思ったので、調べてみました。
結論
まず、osはパッケージではなく、モジュールです。
os.pathモジュールは、osモジュールをimportしたとき、sys.modulesに追加されます。
詳細
当初、osはパッケージだと思っていたのですが、調べてみたらモジュールでした。
$ ll /usr/lib/python2.4/os.py -rw-r--r-- 1 root root 24258 2006-10-12 06:51 /usr/lib/python2.4/os.py
つまり、
import os.path
と記述すると、os/path.pyが読み込まれると思っていたのですが、これは間違いのようです。
ではos.pathモジュールはどこでシステムに追加されているかというと、os.pyの中でした。os.pyの中から、関連している箇所だけを抜き出してみます。
_names = sys.builtin_module_names if 'posix' in _names: import posixpath as path elif 'nt' in _names: import ntpath as path elif 'os2' in _names: if sys.version.find('EMX GCC') == -1: import ntpath as path else: import os2emxpath as path elif 'mac' in _names: import macpath as path elif 'ce' in _names: import ntpath as path elif 'riscos' in _names: import riscospath as path else: raise ImportError, 'no os specific module found' sys.modules['os.path'] = path
すなわち、sys.builtin_module_namesからプラットフォームを判定し、それに応じたモジュールを読み込んで、os.pathモジュールとしているわけです。実際、os.pathを対話プロンプトで表示させると、
>>> import os.path >>> os.path <module 'posixpath' from '/usr/lib/python2.4/posixpath.pyc'>
となり、os/path.pyというファイルから読み込まれているのではないことが分かります。
蛇足ですが、os.pathモジュールとして読み込まれている個々のモジュールの挙動を比較してみました。
>>> import posixpath >>> posixpath.join("foo", "bar") 'foo/bar' >>> import ntpath >>> ntpath.join("foo", "bar") 'foo\\bar' >>> import os2emxpath >>> os2emxpath.join("foo", "bar") 'foo/bar' >>> import macpath >>> macpath.join("foo", "bar") ':foo:bar' >>> import riscospath Traceback (most recent call last): File "<stdin>", line 1, in ? ImportError: No module named riscospath
私の環境では、riscospathモジュールは、インストールもされないようです。