メモ代わり。てきとーに。 いや、ですからてきとーですって。 2年前ぐらいにPythonあたりでメールくれた方、ごめんなさい。メール紛失してしまい無視した形になってしまいました。。。

2008年2月16日土曜日

[Python][お勉強] Python入門(36) - モジュールのインポート

今日もぶりぶりお勉強。

今日はモジュールのインポートについてやる。

まずは、、、
モジュールの作成
モジュールは主にテキストエディタなどで作成するのが普通とのこと。テキストファイルにPythonのコードを入力する。
モジュール内の「トップレベル」で値が代入された変数(名前)は、そのモジュールの「属性」となる。
ちなみに、モジュールをインポートする側のコードのことを「クライアント」と言う。
で、クライアントからはその「属性」を利用できる。
モジュールのファイル名は.py拡張子をつけておく。
モジュールのファイル名のうち、.py拡張子を省いた部分が「モジュールの名前」となる。
したがって、モジュールのファイル名は変数名命ルールに従ってつける必要がある。

さらにモジュールを置いておくディレクトリ名も変数命名ルールに従っておくのが無難とのこと。



モジュールを利用する。
利用するにはimportステートメントかfromステートメントを使う。
importとfromの違いは、ざっくりと

  • importステートメント -- モジュール全体を取り込む
  • fromステートメント -- モジュール中の特定の属性だけをコピーする
な感じか。

importステートメントでモジュールを利用する
モジュールを「module1.py」というファイル名で作成したとする。
中身は

$ cat module1.py
print "start loading"

def aaa(x):
print 'Hello,',x


print "loaded"

$

となっていたとする。
トップレベルからインポートしてみる。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import module1.py
start loading
loaded
Traceback (most recent call last):
File "", line 1, in ?
ImportError: No module named py


import module1.pyと入力するとエラーになる。import、fromでは.py拡張子をつけずにモジュール名
を指定しなければならない。
上記のように.py拡張子をつけてインポートすると、どういうことになるかというと、

module1モジュールのpy属性をインポートする

という意味になってしまう。
さらにimportステートメントなのでpy属性はモジュールである必要がある。

気を取り直して、

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import module1
start loading
loaded
>>> module1.aaa('world')
Hello, world
>>>


.py拡張子をつけずにimportし、その後module1モジュールのaaa属性を呼び出した。
module1の属性を利用するには、利用するたびに"module1."と、モジュール名を指定する必要がある。



fromステートメントでモジュールを利用する。
次はfromステートメントでモジュールを利用してみる。
利用するモジュールは上記のmodule1.py。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from module1 import aaa
start loading
loaded
>>> aaa('world')
Hello, world
>>>


こんどはmodule1モジュールのaaa属性のみを抽出した。
importと違うのはfromでは、

カレントスコープにimport以降で指定した属性をコピーする

ということらしい。
よって、モジュール名を指定しなくてもモジュールの属性を利用できる。
コピーなので、

>>> aaa = (lambda x: 'hi,' + x)
>>> aaa('world')
'hi,world'
>>>


などとやっても、module1の方のaaa属性は影響を受けない。
ただし、aaaが仮に共有リファレンスであった場合、つまりリストなどであった場合はその要素に対する変更がモジュール側にも影響を及ぼす。

$ cat module1.py
print "start loading"

def aaa(x):
print 'Hello,',x

bbb = [1,2,3,4,5]

print "loaded"


のようにbbb属性をリストで追加した。
そしてこれを

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from module1 import bbb
start loading
loaded
>>> bbb
[1, 2, 3, 4, 5]
>>> bbb[0]=10
>>> bbb
[10, 2, 3, 4, 5]


と0番目の要素を上書きする。
モジュール側はどうなっているかというと、

>>> import module1
>>> module1.bbb
[10, 2, 3, 4, 5]
>>>
 

と、bbbの0番目の要素が10に上書きされている。
つまりbbbそのものはコピーされたが、bbbの保持する各要素はリファレンスをそのまま引き継いでいる
ということ。
この辺は他の変数に対するリファレンスの扱いと一緒。


from *ステートメントでモジュールを利用する。
fromステートメントで、import以降に'*'を指定すると、「全ての属性」をコピーする。
module1は1つしか属性がないが、、、

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from module1 import *
start loading
loaded
>>> aaa('hello')
Hello, hello
>>>


などと指定すると、module1の中の全属性がカレントスコープにコピーされる。



インポートしたモジュールの属性へのアクセス
インポートしたモジュールの属性を利用する際にもPython側で属性の特定ルールが存在する。



単純な変数の場合
LEGBルールによって変数がいずれかのスコープから検索される。


完全名の場合
module1.aaaのように書くと、カレントスコープでmodule1が検索され、
その後module1にaaaという属性がないか検索される。


完全パス名の場合
module1.aaa.bbbのように書くと、カレントスコープでmodule1が検索され、
その後module1にaaaという属性がないか検索され、
次にmodule1.aaaにbbbという属性がないか検索される。



な感じにルールがある。
完全名は、モジュールの他にクラス、Cの型など属性を持つ全てのオブジェクトに使用できる。





おしまい。
.

0 コメント: