連載
» 2020年02月10日 05時00分 公開

Pythonチートシート:[Pythonチートシート]モジュール/例外編

モジュールやパッケージのインポート、それらの作成方法、例外の捕捉と送出の基本についてギュッとまとめた。

[かわさきしんじ,Deep Insider編集部]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

「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.」を省略して使用できる

sysモジュールのversion属性の値を表示(実行環境のPythonのバージョンを調べる)

 「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」のみを公開することを明記

アンダースコア「_」を使った命名と__all__変数によって公開するものを制御する例

 このコードを含んだモジュールの名前を「mymod.py」として保存し、これを利用する側でインポートする例を幾つか示す。

from mymod import# 全てをインポート

foo()  # 'foo'
_bar()  # 例外(アンダースコアで始まるものはインポートされないため)
baz()  # 例外(__all__変数で除外されているため)

「from mymod import *」する例

 この場合は、_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')

module1モジュールのコード(mypkg/module1.pyファイル)

 module2.pyファイルのコードは次の通りだ。

def goodbye():
    print('Good-bye')

def test():
    print('test')

module2モジュールのコード(mypkg/subpkg/module2.pyファイル)

 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例外

パッケージのトップレベルをインポートしたが、subpkgはロードされていない

 これはサブモジュールやサブパッケージが実行環境にロードされ、mypkgの属性として設定されていないからだ。トップレベル(あるいはその下層レベル)をインポートしたときに、サブモジュールやサブパッケージがロードされて、「パッケージ名.サブモジュール名.関数名」のようにして利用できるようにするには、__init__.pyファイルに初期化処理を記述する。

 初期化処理では、サブモジュールやサブパッケージを__init__.pyファイル内部でインポートする。トップレベルの__init__.pyファイルにこれを記述した例を以下に示す。

import mypkg.module1  # module1サブモジュールをロード
import mypkg.subpkg  # subpkgサブパッケージをロード

トップレベルの__init__.pyファイルの内容(mypkg/__init__.pyファイル)

 こうすることで、mypkgパッケージのインポート時に、module1サブモジュールとsubpkgサブパッケージがロードされるようになる。そのため、以下のようにmodule1サブモジュールの関数を呼び出せる。

import mypkg

mypkg.module1.hello()  # 'Hello'
mypkg.subpkg.module2.goodbye()  # AttributeError例外

mypkg.module1.hello関数は呼び出せるが、mypkg.subpkg.module2.goodbye関数は呼び出せない

 ただし、subpkgサブパッケージにあるmodule2サブモジュールはロードされていないので、そこで定義されている関数は呼び出せる例外が発生する。これにはsubpkgフォルダにある__init__.pyファイルで以下のようにモジュールをインポートすればよい。

import mypkg.subpkg.module2

サブパッケージの__init__.pyファイルの内容(mypkg/subpkg/__init__.pyファイル)

 __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'

mypkgパッケージを利用するコード(test.pyファイル)

 __init__.pyファイルでは、既に述べたように、「from パッケージ名 import *」を実行する際に、何をインポートするのかを__all__変数で指定することもできる。

 ここでは、例としてトップレベルの__init__.pyファイルのコードを以下のようにしてみよう。

from .module1 import hello
from .subpkg.module2 import goodbye, test

__all__ = ['hello', 'test']

書き換えた後のトップレベルの__init__.pyファイルの内容(mypkg/__init__.pyファイル)

 これはトップレベルで、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例外

「from mypkg import *」形式ではgoodbye関数がインポートされない

 これに対して、次のコードならgoodbye関数もインポートできる。

from mypkg import hello, goodbye, test

hello()  # 'Hello'
test()  # 'test'
goodbye()  # 'Good-bye'

名前を明示すればgoodbye関数もインポート可能

例外

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。