実用の段階に入る

前回まででPythonの基本的な書き方や考え方、関数の使い方について説明した。それほど詳しく取り上げたわけではないが、ここまでの説明でPythonコードのかなりは読めるようになっていると思う。Pythonは今最も人気のあるプログラミング言語の1つだが、人気の理由の1つはこの「学習の簡単さ」にある。

本連載はプログラミング言語を紹介するものではないのだが、Pythonは学習コストを差し引いても習得することで自動化できる作業量のメリットが多いので、もうちょっと説明を継続したい。Pythonの真髄はモジュールやパッケージといったサードパーティ製コードを利用できる点にある。そこにたどり着くまで、もう少しだけPythonの話をしよう。

Pythonのチュートリアルは関数の後に、リストを含む基本的なデータの使い方を説明しているが、その部分は飛ばす。興味がある方はざっと読んでおいてもらえればと思う。次はモジュールから取り上げる。

モジュール

これまでは、Pythonインタプリタでインタラクティブにコードを入力して処理を行う方法を取り上げてきた。この方法は簡単だし、チュートリアルの段階では便利なものだが、インタプリタを終了すれば入力した関数や変数は消えてしまう。永続的に関数を処理しようとすれば、ソースコードをファイルに書いておいて、後から読み込んで利用するというのが本来の使い方だ。この基本単位が「モジュール」と呼ばれている。

以下に、Pythonのソースコードを記述したファイル「fibo.py」(モジュール)を示す。

# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

このファイルは、pythonコマンド(ここではバージョン3.6系を使っているのでpython3コマンド)を実行するとの同じディレクトリに配置しておく。

fibo.pyファイルをカレントディレクトリに置いておく

daichi@ubuntu1804:~$ cat fibo.py
# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result
daichi@ubuntu1804:~$

fibo.pyファイルが置いてあるのと同じディレクトリでPythonインタラクティブシェル(python3コマンド)を起動する。何もしない状態だと、fibo.pyに書いたfib()関数は利用することができない(以下参照)。

daichi@ubuntu1804:~$ python3
Python 3.6.6 (default, Sep 12 2018, 18:26:19)
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> fibo.fib(1000)
  File "<stdin>", line 1
    fibo.fib(1000)
    ^
IndentationError: unexpected indent
>>>

ここで次のように「import」を使用すると、作成した関数を利用することができる。

>>> import fibo
>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib(10000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
>>>

fibo.pyファイルの読み込みは「imoport fibo」で実施する。fibo.pyファイルの中に記述されている関数は、fibo.fib()のように拡張子を抜いたファイル名を指定して利用する必要がある。

「いちいちファイル名を指定するのは面倒」という場合は、いったん次のように変数に代入して別名を用意するという利用方法もある。

>>> fib = fibo.fib
>>> fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fib(10000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
>>>

もう1つ、importする段階で使用する関数を明示するという方法もある。この方法を使うといったん別の変数に代入することなく、明示的に指定した関数をその関数名だけで使用できるようになる。記述例は以下の通りだ。

daichi@ubuntu1804:~$ python3
Python 3.6.6 (default, Sep 12 2018, 18:26:19)
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> fib(1000)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'fib' is not defined
>>> from fibo import fib
>>> fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>>

関数名を指定する方法のimportを使った場合、指定しなかった関数名では使用できないし、逆にファイル名を使った指定もできなくなる。

daichi@ubuntu1804:~$ python3
Python 3.6.6 (default, Sep 12 2018, 18:26:19)
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> fib(1000)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'fib' is not defined
>>> from fibo import fib2
>>> fib(1000)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'fib' is not defined
>>>

「関数名だけで使いたいが、さらに別名でも使いたい」という場合、importする段階で「as」を使って名前を変更するという方法がある。名前の衝突を回避したい場合などには、この方法が生きる。次の使用例では、fibo.pyのfib()関数を「fibonacci()」として使用できるようになっている。

daichi@ubuntu1804:~$ python3
Python 3.6.6 (default, Sep 12 2018, 18:26:19)
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> fibo(1000)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'fibo' is not defined
>>> from fibo import fib as fibonacci
>>> fibo(1000)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'fibo' is not defined
>>> fibonacci(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>>

この例では、モジュールはカレントディレクトリに置いておいたが、実際には「サーチパスに設置されているファイルがモジュールとして読み込める」という仕組みになっている。サーチパスは「sys.path」に書いてある。

>>> import sys
>>> print(sys.path)
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']
>>>

sys.pathは環境変数PYTHONPATHなどから作られる仕組みになっているので、自前でモジュールを用意して利用する場合には、環境変数PYTHONPATHにパスを追加してそこにファイルを置いてから利用する、もしくはsys.path.append(‘パス’)のようにしてPython側からパスを追加して読み込みを行うことになる。

Pythonでサードパーティ製のコードを利用する際、基本的にはモジュール単位だ。ビッグデータ処理向け、統計データ分析向け、組み込みデバイスの制御向け、とそれぞれ用途に応じたコードがすでに開発されており、それらをimportして利用する仕組みになっている。これらが使いこなせれば、かなり実践的にPythonを利用できるところまで踏み込めた感があるだろう。

【参考資料】
The Python Tutorial