[Pythonチートシート]モジュール/例外編:Pythonチートシート
モジュールやパッケージのインポート、それらの作成方法、例外の捕捉と送出の基本についてギュッとまとめた。
今回はこれまでに取り上げてこなかった要素のうち、モジュールとパッケージ、例外についてまとめていく。
なお、モジュールやパッケージの詳細については「Python入門」の以下の記事を参考にしてほしい。
例外については同じく「Python入門」の以下を参考にしてほしい。
モジュールとパッケージのインポート
モジュールやパッケージをインポートするにはimport文を使用する。その主な構文を以下に示す。なお、以下ではモジュール名やパッケージ名を記述する際に単に「モジュール名」とだけ示すことがある。パッケージ内のサブパッケージなども含める際には「パッケージ名」と書くこともある。
# モジュール/パッケージをインポート
import モジュール名
import パッケージ名.サブパッケージ名.モジュール名
# インポートしたモジュールを別名で使用
import モジュール名 as 別名
# モジュール/パッケージから特定のものだけをインポート
from モジュール名 import 識別子(変数、関数、クラス、モジュールなど)
# インポートしたものを別名で使用
from モジュール名 import 識別子 as 別名
# モジュール/パッケージから全てをインポート
from モジュール名 import *
以下に例を示す。
# モジュール/パッケージをインポート
import sys # sysモジュールのインポート
import os.path # osモジュールに含まれるpathモジュールをインポート
# インポートしたモジュールを別名で使用
import numpy as np # numpyモジュールをnpとしてインポート
# モジュール/パッケージから特定のものだけをインポート
from random import randint # randomモジュールのranint関数をインポート
# インポートしたものを別名で使用
from random import randint as rand # random.randint関数をrandとしてインポート
# モジュール/パッケージから全てをインポート
from fractions import * # fractionsモジュールから全てをインポート
モジュール(やパッケージ)をインポートした場合、そこで定義されている変数や関数、クラスには「モジュール名.関数名」「モジュール名.クラス名」のようにしてアクセスする必要がある。以下に例を示す。
import sys # sysモジュールをインポート
print(sys.version_info) # sysモジュールのversion_info属性を使用
from sys import version_info # sysモジュールからversion_info属性をインポート
print(version_info) # これなら「sys.」を省略して使用できる
「from モジュール名 import *」形式では、そのモジュール内で定義されている全ての属性をインポートされる。ただし、この形式だと、現在の名前空間にプログラマーが関知していない多くのものを追加することになり、意図しないうちにそれらが上書きされて、プログラマーが意図したオブジェクト以外のオブジェクトを参照することになったり、どのモジュールで定義されているものかがコードを読む側にハッキリとしなかったりすることがある。そのため、この形式でのインポートは一般には推奨はされていない。
モジュールでの名前の公開(エクスポート)
自分でモジュールを作成する際には、基本的にはそこで定義されているもの全てが、他のモジュールに対して公開される。外部に公開したくないものを制御するには以下の2つの方法がある。
- 公開したくないものの名前をアンダースコア「_」で始め、それが内部使用目的であることを示す
- __all__変数で外部に公開するものの名前を明記する。__all__変数には公開するものの名前(文字列)をリストに列挙する
これらはあくまでも「from モジュール名 import *」形式でインポートを行った際に、特定の名前がインポートされるかどうかを制御するものであり、「from モジュール名 import 特定の名前」としてインポートすることを妨げるものではないことには注意。
公開したくないものを制御する例を以下に示す。
def foo(): # 公開する
print('foo')
def _bar(): # 名前をアンダースコア「_」で始める
print('bar')
def baz(): # __all__変数で公開しないことになっている
print('baz')
__all__ = ['foo'] # 名前「foo」のみを公開することを明記
このコードを含んだモジュールの名前を「mymod.py」として保存し、これを利用する側でインポートする例を幾つか示す。
from mymod import * # 全てをインポート
foo() # 'foo'
_bar() # 例外(アンダースコアで始まるものはインポートされないため)
baz() # 例外(__all__変数で除外されているため)
この場合は、_bar関数は名前がアンダースコアで始まるために、baz関数は__all__変数の要素に含まれていないために、どちらも呼び出そうとするとエラー(NameError例外)が発生する。
ただし、上の例で公開されていなかったものでも、「from モジュール名 import 特定の名前」形式でインポートすることは可能だ。
from mymod import foo, _bar, baz
foo()
_bar()
baz()
パッケージでの名前の公開(エクスポート)
パッケージは一般にフォルダを使って、複数のモジュール(.pyファイル)を構造化したものになる。パッケージを作成する際にはフォルダごとに__init__.pyファイルを置く。これは空でもよいが、何らかの初期化処理を行うこともできる。
ここでは以下の構造を持つパッケージを例とする。
mypkgがパッケージのトップレベルにあり、その下にサブモジュールを含んだ「module1.py」ファイルと、サブパッケージである「subpkg」フォルダがあり、その中にはサブサブモジュールを含んだ「module2.py」ファイルがある。各フォルダには__init__.pyファイルがある。
module1.pyファイルのコードを以下に示す。
def hello():
print('Hello')
module2.pyファイルのコードは次の通りだ。
def goodbye():
print('Good-bye')
def test():
print('test')
2つの__init__.pyファイルの内容はここでは空とする。
この場合、利用者側では以下のようにしてパッケージ、そのサブモジュールなどをインポートできる。
import mypkg # トップレベルをインポート
import mypkg.module1 # サブモジュールをインポート
from mypkg import module1 # サブモジュールをインポート
from mypkg.module1 import hello # サブモジュールから関数をインポート
ただし、「import mypkg」としてトップレベルをインポートした場合、実際にはそのサブモジュールは利用できない(このコードはmypkgと同じ階層に例えば「test.py」のようにして置いたものとする)。
import mypkg
mypkg.subpkg.module2.goodbye() # AttributeError例外
これはサブモジュールやサブパッケージが実行環境にロードされ、mypkgの属性として設定されていないからだ。トップレベル(あるいはその下層レベル)をインポートしたときに、サブモジュールやサブパッケージがロードされて、「パッケージ名.サブモジュール名.関数名」のようにして利用できるようにするには、__init__.pyファイルに初期化処理を記述する。
初期化処理では、サブモジュールやサブパッケージを__init__.pyファイル内部でインポートする。トップレベルの__init__.pyファイルにこれを記述した例を以下に示す。
import mypkg.module1 # module1サブモジュールをロード
import mypkg.subpkg # subpkgサブパッケージをロード
こうすることで、mypkgパッケージのインポート時に、module1サブモジュールとsubpkgサブパッケージがロードされるようになる。そのため、以下のようにmodule1サブモジュールの関数を呼び出せる。
import mypkg
mypkg.module1.hello() # 'Hello'
mypkg.subpkg.module2.goodbye() # AttributeError例外
ただし、subpkgサブパッケージにあるmodule2サブモジュールはロードされていないので、そこで定義されている関数は呼び出せる例外が発生する。これにはsubpkgフォルダにある__init__.pyファイルで以下のようにモジュールをインポートすればよい。
import mypkg.subpkg.module2
__init__.pyファイルはモジュールやパッケージのインポート時に自動的に実行されるので、mypkg/__init__.pyファイルにより、subpkgがインポートされるタイミングで、mypkg/subpkg/__init__.pyファイルも実行される。こうしたロードの連鎖により、うまくパッケージのインポートが行えるようになっている。なお、パッケージ内のサブモジュールやサブパッケージをトップレベルのパッケージ名から指定してインポートすることを「絶対インポート」と呼ぶ。
このようにして、__init__.pyファイルに上の初期化処理を書けば、mypkgパッケージをインポートするだけで、パッケージ内で定義されたものを利用できるようになる(あるいは、トップレベルの__init__.pyファイルで今述べたことに相当するコードを記述してもよい)。
import mypkg
mypkg.module1.hello() # 'Hello'
mypkg.subpkg.module2.goodbye() # 'Good-bye'
__init__.pyファイルでは、既に述べたように、「from パッケージ名 import *」を実行する際に、何をインポートするのかを__all__変数で指定することもできる。
ここでは、例としてトップレベルの__init__.pyファイルのコードを以下のようにしてみよう。
from .module1 import hello
from .subpkg.module2 import goodbye, test
__all__ = ['hello', 'test']
これはトップレベルで、hello関数(module1サブモジュール)とgoodbye関数、test関数(subpkg.module2サブモジュール)をインポートしている。インポートすることにより、その名前が外部に公開されるので、これらは「from mypkg import hello」のようにしてインポートできる。その一方で、__all__変数には'hello'と'test'のみを要素とするリストを代入しているので、「from mypkg import *」形式のインポートではgoodbye関数はインポートされない。
なお、ここで行っている「from .module1 import hello」のようなインポートの仕方を「相対インポート」と呼ぶ。モジュール/パッケージの名前の前にあるドット「.」はパッケージ内で「そのファイル(ここでは__init__.pyファイル)と同じ階層にある」ことを意味する。mypkg/__init__.pyファイルと同じ階層にはmodule1モジュール(module1.pyファイル)とsubpkgサブパッケージ(subpkgフォルダ)があるので、ここではこのように記述している。パッケージ階層が深いときには、「..」「...」のようにして上位の階層を指定していくことも可能だ。
「from mypkg import *」形式でインポートを行う例を示す。
from mypkg import *
hello() # 'Hello'
test() # 'test'
goodbye() # NameError例外
これに対して、次のコードならgoodbye関数もインポートできる。
from mypkg import hello, goodbye, test
hello() # 'Hello'
test() # 'test'
goodbye() # 'Good-bye'
例外
Copyright© Digital Advantage Corp. All Rights Reserved.