現在地: ホーム Dive Into Python 3

難易度: ♦♢♢♢♢

初めてのPythonプログラム

抱えた重荷を聖なる静寂へと葬り去ってはならない。問題を抱えている? それは良いことだ。喜び、飛び込み、調べよう。
Ven. Henepola Gunaratana

 

飛び込む

慣わしに従うならば、私はプログラミングの基本的要素を教えて皆さんをうんざりさせなければならない。そうやって、役に立つものが作れるようになるまで、少しずつ進めていくというわけだ。だが、そんなものはすべて飛ばしてしまおう。以下には完全で、しかもちゃんと動作するPythonのプログラムがある。このプログラムをまったく理解できないとしても、心配はご無用。これから一行ずつ調べていくからだ。しかし、まずはこのプログラムに目を通して、できる範囲でいいので意味を汲み取ってみてほしい。

[humansize.pyをダウンロードする]

SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
            1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}

def approximate_size(size, a_kilobyte_is_1024_bytes=True):
    '''Convert a file size to human-readable form.

    Keyword arguments:
    size -- file size in bytes
    a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
                                if False, use multiples of 1000

    Returns: string

    '''
    if size < 0:
        raise ValueError('number must be non-negative')

    multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
    for suffix in SUFFIXES[multiple]:
        size /= multiple
        if size < multiple:
            return '{0:.1f} {1}'.format(size, suffix)

    raise ValueError('number too large')

if __name__ == '__main__':
    print(approximate_size(1000000000000, False))
    print(approximate_size(1000000000000))

では、このプログラムをコマンドライン上で実行してみよう。Windowsでは次のようにする:

c:\home\diveintopython3\examples> c:\python31\python.exe humansize.py
1.0 TB
931.3 GiB

Mac OS XやLinuxでは次のようにする:

you@localhost:~/diveintopython3/examples$ python3 humansize.py
1.0 TB
931.3 GiB

いったい何が起きたのだろうか? 初めてのPythonプログラムを実行したのだ。Pythonインタプリタをコマンドライン上で呼び出して、実行してほしいスクリプトの名前をPythonに渡したのだ。このスクリプトは1つの関数approximate_size()を定義している。この関数は、正確なファイルサイズをバイト単位で受け取って、(正確ではないが)「美しい」表記のサイズを求める(WindowsのExplorerや、Mac OS XのFinder、LinuxのNautilus/Dolphin/Thunarでこれを見たことがあるだろう。ドキュメントを含むフォルダをマルチカラム形式で表示すると、ドキュメントのアイコン・ドキュメント名・サイズ・ファイルタイプ・最終更新日などを含む表が表示される。仮に、そのフォルダに1093バイトのTODOという名前のファイルが入っているとしたら、ファイルマネージャはTODO 1093 bytesのかわりにTODO 1 KBと表示するだろう。これがapproximate_size()関数の行う処理だ)。

スクリプトの最後を見ると、print(approximate_size(引数))という2つの呼び出しが目にとまるだろう。これらは関数呼び出しだ。まず、いくつかの引数と共にapproximate_size()関数を呼び出して、受け取った戻り値を直接print()関数に渡している。print()関数はPythonの組み込み関数なので、この関数の宣言はどこにも存在しない。このprint()関数はいつでもどこでも使うことができる(組み込みの関数はたくさんあるし、更にもっと多くの関数がモジュールに分けられて存在している。落ち着きなさい、バッタさん)。

ところで、スクリプトを実行すると毎回同じ結果が返ってくるのはなぜだろう? それをこれから調べていくのだ。まずはapproximate_size()関数を見ていこう。

関数を定義する

Pythonには、他の大多数の言語と同じく「関数」がある。しかし、C++のような別個のヘッダファイルや、Pascalのようなinterface/implementationセクションは必要ない。関数が必要なときは、ただ次のように定義するだけでいい:

def approximate_size(size, a_kilobyte_is_1024_bytes=True):

関数定義はキーワードdefによって始まり、その次に関数名が続き、更にその次に括弧で包まれた引数が続く。複数の引数はカンマによって区切られる。

関数が戻り値の型を定義していないことにも注意しよう。Pythonの関数は戻り値のデータ型を指定しないし、戻り値を返すかどうかさえも指定しない(実際にはPythonのすべての関数は値を返す。関数がreturn文を実行する場合はその値を返し、実行しない場合はPythonのNull値であるNoneを返すのだ)。

一部の言語では、関数(戻り値を返す)はfunctionで始まり、サブルーチン(戻り値を返さない)はsubで始まる。Pythonにサブルーチンは存在しない。Pythonではすべてが関数であり、すべての関数は戻り値(それはNoneかもしれない)を返し、すべての関数がdefで始まる。

approximate_size()は2つの引数(sizea_kilobyte_is_1024_bytes)を受け取るが、そのどちらにもデータ型は指定されていない。Pythonでは、変数が明示的に型付けされることは絶対にない。Pythonが変数の型を判断して内部的に追跡するのだ。

Javaやその他の静的型付け言語では、関数の戻り値や引数のデータ型を指定しなければならない。Pythonでは、どんなものに対しても明示的にデータ型を指定することは決してない。代入した値に基づいて、Pythonが内部的にデータ型を追跡するのだ。

オプション引数と名前付き引数

Pythonでは関数の引数にデフォルト値を持たせることができる。つまり、引数に対応する値無しで関数が呼び出された場合には、その引数にデフォルト値が割り当てられるのだ。これに加えて、名前付き引数を使うことによって引数を任意の順序で指定することもできる。

approximate_size()の関数宣言を別の視点から見てみよう:

def approximate_size(size, a_kilobyte_is_1024_bytes=True):

2番目の引数a_kilobyte_is_1024_bytesには、デフォルト値としてTrueが割り当てられている。これは、この引数がオプションだということを意味している。つまり、この関数は、この引数を与えなくとも呼び出すことができ、その場合には第二引数にTrueが渡されたものとPythonは解釈するのだ。

今度はスクリプトの最後の部分を見てみよう:

if __name__ == '__main__':
    print(approximate_size(1000000000000, False))  
    print(approximate_size(1000000000000))         
  1. これはapproximate_size()関数を2つの引数と共に呼び出している。第二引数として明示的にFalseを渡しているので、approximate_size()関数の中でのa_kilobyte_is_1024_bytesの値はFalseになる。
  2. ここではapproximate_size()関数には1つの引数しか渡されていない。しかし、これでも問題はない。第二引数はオプションだからだ! 呼び出し側は第二引数を指定していないので、第二引数は関数宣言で定めた通り、デフォルト値のTrueとなる。

引数の名前を指定して値を関数に渡すこともできる。

>>> from humansize import approximate_size
>>> approximate_size(4000, a_kilobyte_is_1024_bytes=False)       
'4.0 KB'
>>> approximate_size(size=4000, a_kilobyte_is_1024_bytes=False)  
'4.0 KB'
>>> approximate_size(a_kilobyte_is_1024_bytes=False, size=4000)  
'4.0 KB'
>>> approximate_size(a_kilobyte_is_1024_bytes=False, 4000)       
  File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
>>> approximate_size(size=4000, False)                           
  File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
  1. これは、第一引数 (size) に4000を渡し、a_kilobyte_is_1024_bytesという名前の引数にFalseを渡した上で、approximate_size()関数を呼び出している(a_kilobyte_is_1024_bytesという名前の引数は偶然にも第二引数だが、それに意味がないことはすぐに分かる)。
  2. これは、sizeという名前の引数 に4000を渡し、a_kilobyte_is_1024_bytesという名前の引数にFalseを渡した上で、approximate_size()関数を呼び出している(これらの引数は関数定義で並べたのと同じ順序で並んでいるが、これにも意味はない)。
  3. これは、a_kilobyte_is_1024_bytesという名前の引数にFalseを渡し、size という名前の引数に4000を渡して、approximate_size()関数を呼び出している(順序は関係ないと言った意味が分かっただろうか?)。
  4. この呼び出しは失敗する。その理由は、名前付き引数の後ろに名前付けされていない(位置に依存する)引数が置かれているからで、こういう書き方はPythonでは許されていないのだ。引数リストを左から右へ読んだときに名前付き引数が現れたら、それ以降の引数には必ず名前を付けなければならない。
  5. 一つ前の呼び出しと同様の理由で、この呼び出しも失敗する。これは意外だろうか? 引数sizeとして4000という値を渡したので、Falsea_kilobyte_is_1024_bytesを意味するのは「明らか」なのだが、Pythonはそのように解釈しないのだ。名前付き引数を使ったら、その右にある引数にはすべて名前を付けなければならない。

読みやすいコードを書く

「コードのドキュメントを書くことの重要性」についての長ったらしいスピーチをして、あなたを退屈させたくはない。知っておいて欲しいのは、コードは一度だけ書かれるが何度も読まれるということと、コードの最も重要な読者というのは、コードを書いてから6ヶ月後の(i.e.どこかを修正する必要があるのだけど、コードの中身をすっかり忘れてしまってる)あなた自身だということだけだ。Pythonは読みやすいコードを容易に書けるようになっているので、この利点をちゃんと生かそう。きっと6ヶ月もすれば私に感謝することになるよ。

ドキュメンテーション文字列

Pythonの関数にドキュメンテーション文字列(略してdocstringという)を与えることで、その関数のドキュメントを書くことができる。このプログラムではapproximate_size()関数がdocstringを持っている:

def approximate_size(size, a_kilobyte_is_1024_bytes=True):
    '''Convert a file size to human-readable form.

    Keyword arguments:
    size -- file size in bytes
    a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
                                if False, use multiples of 1000

    Returns: string

    '''

三重クォートは複数行文字列を表す。開始クォートと終了クォートの間にあるすべてのものが単一の文字列の一部と解釈され、改行文字や行の先頭にある空白、その他のクォート文字も文字列とみなされる。複数行文字列はどんな場所でも使えるが、一番よく目にするのはdocstringを定義するために使われているものだろう。

三重クォートは、シングルクォートとダブルクォートの両方を含んだ文字列を定義する簡易な方法でもある。これはPerl 5のqq/.../に似ている。

三重クォートの中にあるすべてのものがこの関数のdocstringであり、この関数が何をするのかに関するドキュメントになっている。docstringをもし付けるなら、関数の一番初め(つまり関数宣言の次の行)で定義しなければならない。形式的には、docstringが無くてもプログラムは動くのだが、これは常に付けておいたほうがいい。今までに受講したどのプログラミングの授業でもこれをさんざん聞かされていることは知っている。しかし、Pythonではドキュメントを付ける意義が更にもう一つ存在する。docstringは実行時に関数の属性として利用できるのだ。

多くのPython用IDEは、文脈依存のドキュメントを提供するためにdocstringを使っているので、関数名を入力すると、その関数のdocstringがツールチップとして表示される。これは非常に便利なものになり得るが、そのためには良いdocstringを書いておかなければならない。

import検索パス

先へ進む前に、ライブラリの検索パスについて簡単に触れておきたい。モジュールをインポートしようとすると、Pythonは何ヶ所かを参照する。具体的に言うと、Pythonはsys.pathに定められたすべてのディレクトリの中を見る。sys.pathは単なるリストなので、標準的なリストのメソッドを使って、簡単にそれを見たり、内容を変更したりできる(リストについてはネイティブデータ型で詳しく学ぶ)。

>>> import sys                                                 
>>> sys.path                                                   
['',
 '/usr/lib/python31.zip',
 '/usr/lib/python3.1',
 '/usr/lib/python3.1/plat-linux2@EXTRAMACHDEPPATH@',
 '/usr/lib/python3.1/lib-dynload',
 '/usr/lib/python3.1/dist-packages',
 '/usr/local/lib/python3.1/dist-packages']
>>> sys                                                        
<module 'sys' (built-in)>
>>> sys.path.insert(0, '/home/mark/diveintopython3/examples')  
>>> sys.path                                                   
['/home/mark/diveintopython3/examples',
 '',
 '/usr/lib/python31.zip',
 '/usr/lib/python3.1',
 '/usr/lib/python3.1/plat-linux2@EXTRAMACHDEPPATH@',
 '/usr/lib/python3.1/lib-dynload',
 '/usr/lib/python3.1/dist-packages',
 '/usr/local/lib/python3.1/dist-packages']
  1. sysモジュールをインポートすることで、そのモジュールのすべての関数と属性が利用できるようになる。
  2. sys.pathは現在の検索パスを構成しているディレクトリ名のリストだ(皆さんの環境では違うものが表示されるだろう。これはOSや、Pythonのバージョン、Pythonがインストールされた場所に依存する)。Pythonはこれらのディレクトリを(この順番で)見ていき、インポートしようとしている名前にマッチする.pyファイルを探す。
  3. 実を言うと、今述べたことは正しくない。真相はもっと複雑で、すべてのモジュールが.py ファイルの形で格納されているとは限らないのだ。たとえばsysのようないくつかのモジュールは、組み込みモジュールというものであり、これらは実際にはPython自体に埋め込まれている。組み込みモジュールは通常のモジュールと同じように振る舞うが、このモジュールのPythonのソースコードを手に入れることはできない。組み込みモジュールはPythonでは書かれていないのだ!(sysモジュールはC言語で書かれている)
  4. sys.pathにディレクトリ名を追加することによって、実行時に新たなディレクトリをPythonの検索パスに追加できる。これによって、Pythonはモジュールをインポートするときに、そのディレクトリも参照するようになる。この効果はPythonの実行が終了するまで続く。
  5. sys.path.insert(0, new_path)を使用して、新しいディレクトリをsys.pathリストの先頭に追加した。これで、このディレクトリがPythonの検索パスの一番初めに来ることになる。ほとんどの場合はこれで用が済んでしまうだろう。万が一、名前の衝突が起きたとしても(例えば、あるライブラリのバージョン2がPythonに搭載されているが、あなたはバージョン3を使いたいという場合)、こうすれば確実にお望みのモジュールが発見され、Python付属のモジュールの代わりに使われることになる。

あらゆるものがオブジェクト

忘れてしまった人のためにもう一度言っておくと、Pythonの関数は属性を持っており、それらの属性は実行時に利用できる。Pythonでは、他のあらゆるものと同様に、関数もオブジェクトだ。

Pythonの対話シェルを起動し、次のようにしよう:

>>> import humansize                               
>>> print(humansize.approximate_size(4096, True))  
4.0 KiB
>>> print(humansize.approximate_size.__doc__)      
Convert a file size to human-readable form.

    Keyword arguments:
    size -- file size in bytes
    a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
                                if False, use multiples of 1000

    Returns: string

  1. 1行目はhumansizeプログラムをモジュールとしてインポートしている。モジュールはコードのかたまりであり、対話的に使うこともできるし、より大きなプログラムから使うこともできる。モジュールをインポートすると、そのモジュールが公開している関数・クラス・属性を参照できるようになる。あるモジュールの中で他のモジュールにある機能にアクセスしたい場合にもこれと同じようにすればいいし、この操作をPython対話シェルの中で行うこともできる。これは重要な概念であり、この本を通して何度も目にすることになる。
  2. インポートされたモジュールの中で定義された関数を使いたいときは、モジュール名を含めて書く必要がある。つまり、単にapproximate_sizeと書くことはできず、humansize.approximate_sizeと書かなければならない。もし、Javaのクラスを使ったことがあるなら、なんとなく見慣れた感じがするだろう。
  3. 関数を呼び出すのではなく、関数の属性の1つである__doc__を呼び出している。

Pythonのimportは、Perlのrequireに似ている。Pythonのモジュールをimportすると、モジュールの関数はモジュール.関数でアクセスできる。Perlのモジュールをrequireすると、モジュールの関数は モジュール::関数でアクセスできる。

オブジェクトとは何か?

Pythonではあらゆるものがオブジェクトであり、すべてのオブジェクトは属性とメソッドを持つことができる。すべての関数は組み込み属性の__doc__を持っており、これはその関数のソースコード上に定義されたdocstring を返す。sysモジュールは(他の属性に混じって)pathという属性を持つオブジェクトだ。その他も同じだ。

ところで、まだ根本的な質問に答えていなかった: オブジェクトとは何なのか? この「オブジェクト」の定義はプログラミング言語によってまちまちだ。一部の言語では、すべてのオブジェクトは属性とメソッドを持たなければならないと定めている。別の言語では、オブジェクトはサブクラス化できるものを指している。Pythonでは、オブジェクトの定義はもっと緩くなっている。一部のオブジェクトは属性もメソッドも持たないが、持つこともできる。全てのオブジェクトがサブクラス化できるわけではないが、それを変数に代入することができ、関数の引数として渡すことができるという意味では、すべてがオブジェクトなのだ。

何らかのプログラミングの文脈で「ファーストクラスオブジェクト」という用語を聞いたことがある人もいるだろう。Pythonでは、関数はファーストクラスオブジェクトだ。したがって、関数を他の関数の引数として渡すことができる。モジュールもファーストクラスオブジェクトだ。したがって、モジュールをまるごと関数の引数として渡すことができる。クラスもファーストクラスオブジェクトであるし、クラスの個々のインスタンスもファーストクラスオブジェクトだ。

これは重要なことなので、Pythonではあらゆるのものがオブジェクトという言葉を忘れないように、私はこれからも何度か繰り返して言うつもりだ。文字列はオブジェクト。リストはオブジェクト。関数はオブジェクト。クラスはオブジェクト。クラスインスタンスはオブジェクト。モジュールでさえもオブジェクトだ。

コードをインデントする

Pythonの関数は、関数コードの開始と終了を示すための明示的なbegin/endや波括弧{}を持たない。唯一の区切り文字はコロン (:) とコード自体のインデントだけだ。

def approximate_size(size, a_kilobyte_is_1024_bytes=True):  
    if size < 0:                                            
        raise ValueError('number must be non-negative')     
                                                            
    multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
    for suffix in SUFFIXES[multiple]:                       
        size /= multiple
        if size < multiple:
            return '{0:.1f} {1}'.format(size, suffix)

    raise ValueError('number too large')
  1. コードブロックはインデントによって定められる。ここでは「コードブロック」という言葉は、関数、if文、forループ、whileループなどを表している。インデントでブロックが始まり、インデントの解除でブロックが終わる。ブロックを明示するための波括弧・括弧・キーワードなどは存在しない。ゆえに、Pythonでは空白が重要な意味を持ち、空白に一貫性を持たせなければならないことになる。この例では、関数コードは4個のスペースでインデントされている。インデントは必ずしも4個のスペースである必要はなく、空白の数に一貫性がありさえすればよい。次にインデントされていない行が現れたら、それが関数の終了を示す印となる。
  2. Pythonでは、if 文はコードブロックを伴う。もし if 文が真と評価されれば、インデントされたブロックが実行され、そうでなければelseブロックが(もしあれば)実行される。式の周りに括弧がないないことに注意しよう。
  3. この行はifコードブロックの中にある。このraise文は、size < 0のときに限って(ValueError型の)例外を送出するのだ。
  4. これは関数の終わりではない。完全に空白の行は無視される。空行はコードを読みやすくしてくれるが、コードブロックの終了とはみなされない。この関数は次行以降も継続する。
  5. forループもコードブロックの開始を示す印だ。コードブロックは複数の行を含むことができ、同じインデント量にしている限り継続する。このforループは3行のコードを含んでいる。インデント以外に複数行のコードブロックを表す記法は存在しない。だから、インデントだけを整えて、後は気にせず進めていけばいい。

初めはインデントに抵抗を感じたり、Fortranとの類似性を意地悪く言いたてたりするかもしれないが、次第にこのインデントを受け入れて、その利点を理解するようになろうだろう。インデントの大きな利点の一つは、すべてのPythonプログラムが同じような体裁を持つようになることだ。これはインデントが単なるスタイルではなく言語上の要求であることの帰結であり、他人が書いたコードを読んで理解することをより容易にしてくれる。

Pythonは、文を分けるために改行を使い、コードブロックを分けるためにコロンとインデントを使う。C++やJavaは文を分けるためにセミコロンを使い、コードブロックを分けるのに波括弧を使う。

例外

例外はPythonのあらゆる所にある。Pythonの事実上すべての標準モジュールが例外を使用しているし、Python自体も実に様々な状況において例外を送出する。この本を通してそれを何度も見かけることになる。

例外とは何か? 通常これはエラーであり、何かがうまくいかなかったことを知らせるものだ(エラーではない例外もあるが、現時点ではそれは気にしないでおこう)。一部のプログラミング言語は、エラーを戻り値として返すことを奨励しており、あなたは戻り値をチェックする。Pythonは例外の使用を奨励しており、あなたはそれを処理するのだ。

Pythonシェルでエラーが起きたときは、シェルは例外の詳細とそれがどうやって起きたのかを表示し、処理を止めてしまう。これは未処理例外とよばれる。例外が発生したときに、これを明示的に見つけて処理するコードが1つも存在しない場合は、例外がPythonシェルのトップレベルまで浮き上がってきて、デバッグ情報を吐き出し、それで実行が終了する。シェルでは、これはたいした問題にはならないが、実際のPythonプログラムが動作している最中にこれが起きた場合には、例外が処理されない限り、プログラムが悲鳴を上げて停止することになる。これは望ましい動作かもしれないし、そうでないかもしれない。

Javaとは違い、Pythonの関数は、自身がどのような例外を送出するのかを宣言しない。発生しうる例外のうち捕捉すべきものを見定めるのはあなたの責任だ。

例外は、必ずしもプログラムのクラッシュを引き起こすわけではない。例外は処理できるのだ。例外の原因が完全にコードのバグ(存在しない変数にアクセスするなどの)であることもあるが、例外の発生が予期できることもある。ファイルを開こうとしたとき、そのファイルは存在しないかもしれない。モジュールをインポートしようとするとき、そのモジュールはインストールされていないかもしれない。データベースに接続しようとしたとき、そのデータベースは利用できないかもしれないし、アクセスするための適切なセキュリティ証明書を持っていないかもしれない。もし、そのコードが例外を発生させることを知っているのならば、try...exceptブロックを使って例外を処理すべきだ。

Pythonでは、例外を処理するためにtry...exceptブロック使い、例外を生成するためにraise文を使う。JavaやC++では、例外を処理するためにtry...catchブロック使い、例外を生成するためにthrow文を使う。

approximate_size()は2つの異なる状況において例外を発生する: sizeが想定よりも大きい場合と、ゼロより小さい場合だ。

if size < 0:
    raise ValueError('number must be non-negative')

例外を発生させる構文は実にシンプルだ。raise文を使い、その後に例外名と、オプションでデバッグ用の人間が読める文字列を置く。この構文は関数呼び出しに似ている(実際に、例外はクラスとして実装されており、raiseValueErrorクラスのインスタンスを生成し、'number must be non-negative'という文字列をインスタンスの初期化メソッドに渡す。しかしこの話は先走りすぎだ!)。

例外は、それを発生させた関数の中で処理される必要はない。もし、その関数が例外を処理しない場合は、例外はその関数を呼び出している関数へ渡され、更にその関数を呼び出している関数に渡され、以降同様に「スタックをさかのぼる」。もしどの関数でも例外が処理されない場合は、プログラムはクラッシュし、Pythonが "Traceback" というものを標準エラー出力に出力し、一連の流れが終わる。繰り返すが、これは望む結果かもしれない。それはあなたのプログラムが何をするのかによるのだ。

インポートエラーを捕捉する

Pythonの組み込み例外の1つに ImportError があり、これはモジュールをインポートしようとして失敗したときに発生する。これは様々な理由で起きうるが、最も単純なケースは、インポートしようとしたモジュールがimport検索パスのなかに見つからない場合だ。これを使えば、プログラムにオプション機能を追加できる。例えば、chardetライブラリは文字コードの自動判定を行う機能を備えている。あなたのプログラムは、このライブラリがもし存在すればこれを使いたいが、ユーザがこれをインストールしていない場合でもそのまま実行を続けたいかもしれない。このような処理は try...except ブロックを使えば実現できる。

try:
  import chardet
except ImportError:
  chardet = None

これ以降、chardetモジュールの存在を単純なif文で判断できる。

if chardet:
  # do something
else:
  # continue anyway

ImportError例外が使われるもう一つの一般的な場面は、2つのモジュールが共通のAPIを実装しているが、どちらか一方が他方より望ましい(高速だったり、メモリ使用が少ないなど)という場合だ。この時、まず一方のモジュールをインポートしようとしてみて、それが失敗したときには、もう一方のモジュールへフォールバックできる。例えば、XMLの章ではElementTree APIと呼ばれる共通のAPIを実装した2つのモジュールについて触れることになる。1つはlxmlというサードパーティのモジュールで、自分でインストールしなければ使えない。2つ目はxml.etree.ElementTreeというモジュールで、これはPython 3の標準ライブラリに入っているものの処理速度が遅い。

try:
    from lxml import etree
except ImportError:
    import xml.etree.ElementTree as etree

このtry...exceptブロックを抜けるころには、何らかのモジュールがインポートされて、それをetreeという名前で呼び出せるようになっている。両者のモジュールは共通のAPIを実装しているので、コードの他の部分では、どちらのモジュールがインポートされたのかを気にする必要はない。そして、モジュールは常にetreeという名前でインポートされるので、違う名前のモジュールを呼び分けるために、コードのあちこちをif文で汚す必要はない。

未束縛の変数

approximate_size()関数の次の行を別の視点から見てみよう:

multiple = 1024 if a_kilobyte_is_1024_bytes else 1000

変数multipleの宣言はどこにも行なっておらず、単にmultipleに値を代入しているだけだ。これで問題ない。Pythonはそうできるようになっているのだ。Pythonが許さないのは、値がまだ代入されていない変数を参照することだ。それをしようとすると、NameError例外が発生する。

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> x = 1
>>> x
1

いつかこのことでPythonに感謝することになるだろう。

あらゆるものにおいて大文字と小文字が区別される

Pythonにおけるすべての名前: 変数名・関数名・クラス名・モジュール名・例外名では大文字と小文字が区別される。取得・設定・呼び出し・生成・インポート・送出ができるものなら、大文字と小文字が区別されるのだ。

>>> an_integer = 1
>>> an_integer
1
>>> AN_INTEGER
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'AN_INTEGER' is not defined
>>> An_Integer
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'An_Integer' is not defined
>>> an_inteGer
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'an_inteGer' is not defined

などなど。

スクリプトを実行する

Pythonのモジュールはオブジェクトであり、いくつかの便利な属性を持っている。これを使えば、モジュールを書いたときに、そのモジュールを簡単にテストできるようになる。Pythonファイルをコマンドライン上で走らせた場合だけに実行される特別なブロックを書き加えればいいのだ。humansize.pyの最後の数行を見てみよう:


if __name__ == '__main__':
    print(approximate_size(1000000000000, False))
    print(approximate_size(1000000000000))

C言語と同様に、Pythonは==を比較のために使い、=を代入のために使う。C言語とは違い、Pythonはインラインの代入をサポートしていないので、比較をするつもりで誤って代入をしてしまう可能性はない。

このif文がやっている特殊なこととは何だろう? まず、モジュールはオブジェクトであり、すべてのモジュールは__name__という組み込みの属性を持っている。モジュールの__name__の値は、そのモジュールをどのように使っているかに応じて決まる。そのモジュールを import した場合は、__name__はモジュールのファイル名からディレクトリ名や拡張子を取り除いたものになる。

>>> import humansize
>>> humansize.__name__
'humansize'

しかしモジュールは、スタンドアローンのプログラムとして直接実行することもできる。この場合には__name__は特別なデフォルト値の"__main__"になる。Pythonはこの if 文を評価し、その式が真だということを知り、ifのコードブロックを実行する。この例では、2つの値が表示される。

c:\home\diveintopython3> c:\python31\python.exe humansize.py
1.0 TB
931.3 GiB

そして、これがあなたの初めてのPythonプログラムだ!

もっと知りたい人のために

© 2001– Mark Pilgrim
© Fukada, Fujimoto(日本語版)