このブログを検索

第1章 はじめてのPythonプログラム

1.1.  没頭しよう


動くプログラムが書けるようになる前に、基本ばかりだと嫌になってしまいます。まずは全部スキップしましょう。

こちらの完成されたPythonプログラムを見てください。どうなっているか解らなくても、これから1行ずつ詳しく見ていくので心配することはありません。とにかく1度、解るところだけでも通して読んでみましょう。
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))
このプログラムをhumansize.pyに保存して、コマンドラインで実行します。
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に実行させるスクリプトの名前を入力しました。スクリプト内には関数 approximate_size() が定義されていて、ファイルサイズをバイト単位で近似的に「繰り上げて」計算しています。

(あなたが使っているのはWindowsエクスプローラ、Mac OS X Finder、Nautilus、Dolphin、Thunar on Linuxのどれかだと思います。ドキュメントがありフォルダを一覧リストで表示すると、ドキュメントのアイコン、名前、サイズ、種類、更新日時などが表示されます。フォルダにTODOという名前の1093バイトのファイルがある場合、ファイルマネージャではTODO 1093Bではなく、TODO 1KBと表示されます。まさにこれがapproximate_size() 関数のやっていることです。
スクリプトの最後に、print(approximate_size(arguments))が2回書かれています。これらは関数を呼び出していて、1つ目はapproximate_size()関数を呼び出して引数の値を渡していて、2つ目は返り値をそのままprint()関数に渡しています。print()関数はビルトイン関数なので、いつでもどこででも宣言なしで使えます。ビルトイン関数は沢山あり、さらに多くの関数がモジュールに分かれています。我慢ですよ、バッタ君[訳注]。)

では、コマンドラインでスクリプトを実行すると、同じ結果が毎回出るのはなぜでしょうか?それを理解するために、まずapproximate_size() 関数を見ていきましょう。

(訳注:バッタ君?・・・原文では"Patience, young grasshopper"となっており、アメリカのカンフー映画の中で、少年が師匠から「grasshopper」というアダ名を付けられる場面があり、それに由来します。焦る初心者に忍耐を説く先生の言葉。)

1.2.  関数の宣言


他のプログラミング言語と同様に、Pythonには関数が存在しますが、C++におけるヘッダファイルや、Pascalにおけるインターフェイス/実装セクションは必要ありません。関数が必要なときは、このように宣言します。
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
関数を宣言するためには、defというキーワードを最初に書いて、続けて関数の名前、括弧の中に引数を書きます。引数が複数の場合は、コンマで区切ります。

関数は返り値のデータタイプを定義しないことに注意しましょう。Pythonの関数は返り値のデータタイプを特に定めませんし、値を返すかどうかさえも規定しません。

(実際は、すべてのPython関数は値を返しています。関数がreturnを実行すればその値を返し、実行しない場合はPythonのNull値であるNoneを返します。)

あるプログラミング言語では、値を返す関数はfunctionから始まり、サブルーチン(値を返さない)はsubから始まります。Pythonにはサブルーチンは存在しないため、すべてが関数です。すべての関数はdefから始まり、1つの値を返します(Noneの場合もあります)。

approximate_size() 関数は、sizea_kilobyte_is_1024_bytesの2つの引数をとりますが、いずれもデータタイプが規定されていません。Pythonでは、変数を明示的に記述する必要は全くありません。Python内部でどのような変数かを解釈し、記憶しています。

Javaなどの静的に記述された言語では、関数の返り値、引数のデータタイプを必ず明示します。Pythonではどんなものもデータタイプを明示する必要はありません。割り当てられた値によって、Pythonが内部でデータタイプを記憶しています。

1.2.1.  オプションの引数、名前付き引数


Pythonでは、引数にデフォルト値を設定できます。引数なしで関数が呼び出された場合は、デフォルト値が入ります。また、引数に名前をつけると、どのような順序でも書くことができます。

もう一度、approximate_size()関数の宣言を見てみましょう。
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
2番目の引数(a_kilobyte_is_1024_bytes)はデフォルト値としてTrueを設定しているため、オプションになります。つまり、2番目の引数がなくても関数を呼び出すことができて、その場合デフォルト値であるTrueが与えられているとPythonは解釈します。

では、スクリプトの最後の部分を見てみましょう。
if __name__ == '__main__':
    print(approximate_size(1000000000000, False))  # ①
    print(approximate_size(1000000000000))         # ②
①approximate_size()関数を2つの引数で呼び出しています。approximate_size()関数に、明示的に2番目の値としてFalseを渡しているのでa_kilobyte_is_1024_bytesはFalseになります。

②approximate_size()関数を1つの引数で呼び出していますが、2番目の引数はオプションなので、なくても問題はありません。2番目の引数は明示されていないので、関数宣言で定義されたデフォルト値の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 "", line 1
SyntaxError: non-keyword arg after keyword arg
>>> approximate_size(size=4000, False)                           # ⑤
  File "", line 1
SyntaxError: non-keyword arg after keyword arg
①approximate_size()関数を呼び出します。1つ目の引数は4000、2番目の引数はa_kilobyte_is_1024_bytesという名前でFalseを渡しています(すぐあとでわかるように、名前ありの引数が2番目であることは特に重要ではありません。)

②approximate_size()関数を呼び出し、sizeという名前の引数4000とa_kilobyte_is_1024_bytesという名前の引数Falseを渡しています(名前ありの2つの引数の順が関数での宣言の順と同じですが、これも特に重要ではありません。)

③a_kilobyte_is_1024_bytesという名前の引数Falseを渡し、sizeという名前の引数で4000を渡しています(どうですか?順番は関係ないと言ったとおりでしょう?)

④この呼び出しは失敗します。なぜなら、名前ありの引数のあとに名前なしの引数を渡しているからです。引数のリストは左から右へと読むため、名前ありの引数が出てきたら、その後はすべて名前ありでなくてはならないのです。

⑤この呼び出しも失敗します。理由は④と同じです。びっくりしましたか?4000という引数の名前がsizeで、Falseという値は”どうみても”a_kilobyte_is_1024_bytesの値として渡されています。しかし、Pythonはそのように解釈してくれません。名前付きの引数があれば、そこから右のすべての引数は名前が必要です。

1.3.  読みやすいコードを書く


指を振りかざしながらコード記法の重要性を説いて、うんざりさせるつもりはありません。コードは1度書かれたあとに何度も読まれる、ということを知っておいて欲しいだけです。そのコードを書いてから半年後の自分自身が、一番重要な読者になるのです(すべて忘れてしまったあとに修正する必要が出てきます。)Pythonでは、読みやすいコードを容易に書けますから、その恩恵にあずかりましょう。半年後、感謝することになりますよ。

ドキュメンテーション文字列(docstring)を使ってPython関数にコメントを入れることができます。以下のapproximate_size()関数にはドキュメンテーション文字列が入っています。
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

    '''
トリプルクォート( ''' )は、複数行コメントという意味になります。開始クォートから終了クォートの間にあるものはすべて―改行、スペース、他の引用符を含めて― コメント行とみなされます。コードのどの部分でも使えますが、一番よく使われるのはドキュメンテーション文字列です。

👉 トリプルクォートは、シングルクォート、ダブルクォートどちらでも作れて、コメント文を定義できます。Perl5のqq/.../のようなものです。

トリプルクォートに囲まれたすべての部分は、関数のドキュメンテーション文字列となってその関数がどういうものかが記述されることになります。ドキュメンテーション文字列は、関数の最初、宣言した次の行に書かれます。絶対に必要ということではないですが、なるべく書いたほうがよいでしょう。これはどんなプログラミング講座を受けても聞く話でしょうが、Pythonには素晴らしい特典機能があります。ランタイム上で、ドキュメンテーション文字列を関数の属性として取得することができるのです。

👉 たいていのPython IDEでは、その場での説明文としてdocstringを使います。つまり、関数名をタイプすると、その関数のdocstringがtipsとして現れます。非常に便利ですが、ドキュメンテーション文字列をどれだけ上手く書けるかが重要になってきます。

1.4. インポート・サーチパス


先に進む前に、ライブラリ・サーチパスについて少し説明します。モジュールをインポートするときに、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                                                        # ③

>>> 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']
①sysモジュールをインポートすると、sysの関数と属性がすべて使えるようになります。

②sys.pathはディレクトリ名のリストで、カレントサーチパスを構成しています(OS、Pythonのバージョン、インストール先によって出力は異なります)。Pythonはインポートする.pyファイルを探すために、これらのディレクトリを(表示順に)見ていきます。

③厳密には、嘘です。真実はもっと複雑です。というのは、すべてのファイルの形式が.pyというわけではないからです。例えば、ビルトインモジュールというものがあって、それらはPython自身に書かれています。ビルトインモジュールは通常のモジュールのように振る舞いますが、ソースコードを見ることはできません。なぜなら、Pythonの中に書かれているからです!(Python本体のように、これらのビルトインモジュールはC言語で書かれています。)

④Pythonの起動中に、新しいディレクトリをサーチパスに追加できます。sys.pathにディレクトリ名を追加すると、Pythonはインポートするときに、このディレクトリ内も探すようになります。この変更は、Pythonが起動している間だけ保持されます。

⑤sys.path.insert(0, new_path)とすると、new_pathtという新しいディレクトリは、sys.pathリストの最初の項目として追加されます。つまり、Pythonが最初にサーチするということです。insertコマンドは、ほとんどの場合この目的のために使われます。同じ名前のモジュールで別バージョンを使いたいとき(例えば、あるライブラリのバージョン2がPythonにビルトインされているが、バージョン3を使いたいとき)、insertを行うとPythonに元からあるモジュールではなく、先に見つかるように指定したモジュールが使用されます。

1.5. すべてはオブジェクトである


もう1度言いますが、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
①humansizeプログラムをモジュールとしてインポートしています。モジュールは、コードのひとかたまりで、対話形式でも使えますし、大規模なPythonプログラムからも呼び出すことができます。モジュールを一度インポートすると、モジュール内のパブリック関数(自由にアクセスできる関数)、クラス、属性をどれでも参照できます。

モジュールから他のモジュールへのアクセスは、このような関数を使った方法でも可能ですが、Python対話型シェルでも同じことができます。これは重要な考え方で、この本で何度も見ることになるでしょう。

②インポートされたモジュール内で定義されている関数を使うときは、モジュール名を含めて記述します。つまり、approximate_sizeではなく、humansize.approximate_sizeと書きます。もしJavaでクラスを使ったことがあるならば、見覚えがある書き方かもしれませんね。

③関数を呼び出すのではなく、関数の属性__doc__を使って、ドキュメンテーション文字列を呼び出しています。

👉Pythonのimportは、Perlのrequireに似ています。Pythonではモジュールをimportしたあとは、module.functionで関数にアクセスできます。Perlではモジュールをrequireしたあとは、module::functionで関数にアクセスできます。

1.5.1. オブジェクトとは何か?


Pythonではすべてのものがオブジェクトで、属性やメソッドを持つことができます。関数には必ずビルトイン属性の__doc__があり、これは関数のソースに書かれたドキュメンテーション文字列を返します。sysモジュールはpathという属性も持っています。他にもさまざまなものがあります。

しかし、これでは本質的な問いに答えていません。オブジェクトとは何でしょうか?種々のプログラミング言語は、”オブジェクト”をそれぞれ定義しています。ある言語では、すべてのオブジェクトは属性とメソッドを持つものだと定義し、ある言語ではすべてのオブジェクトはサブクラス化できると定義しています。Pythonでは、オブジェクトの定義はゆるやかです。属性とメソッドを持つことができるのに、両方とも持たないオブジェクトもあります。すべてのオブジェクトがサブクラス化できるわけではありません。しかし、変数に代入できる、関数に引数として渡すことができる、という意味でPythonのすべてのものはオブジェクトなのです。

”ファーストクラスオブジェクト”という言葉を、他のプログラミング本で見たことがあるかもしれません。Pythonでは、関数がファーストクラスオブジェクトです。関数を引数として、他の関数に渡すことができます。モジュールはファーストクラスオブジェクトです。モジュール全体を引数として、関数に渡すことができます。クラスはファーストクラスオブジェクトですし、クラスの個々のインスタンスも、ファーストクラスオブジェクトです。

これは重要なことですので、忘れないように何度も繰り返しておきます。Pythonではすべてがオブジェクトです。文字列はオブジェクト。リストはオブジェクト。関数はオブジェクト。クラスはオブジェクト。クラスインスタンスはオブジェクト。モジュールですら、オブジェクトです。

1.6. インデント


Pythonの関数には、明確な始まりや終わりを示すものがありません。関数のコードが始まったり、終わったりするところに波括弧があるわけでもありません。デリミタはコロン(:)とコード自身のインデントだけです。
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')
①コードブロックはインデントで区切られます。ここでいう”コードブロック”とは、関数、if文、forループ、whileループなどのかたまりです。インデントでブロックが始まり、インデント解除でブロックが終わります。括弧、ブラケット、キーワードは必要はありませんが、空白スペースが重要で、揃っていなければなりません。この例では、関数のコードはスペース4つでインデントされています。スペースが4つである必要はありませんが、数が揃っている必要があります。インデントされていない行が出てきたら、そこが関数の終わりです。

②Pythonでは、if文にはコードブロックが続きます。if文がTrueであれば、インデントされたブロックが実行されます。Trueでなければelseブロックに移ります(elseブロックがある場合)。この表現には括弧がないことに注目してください。

③この行はifブロックの中にあります。raise文はsize<0が満たされたときのみ、例外(ValueError型)を出します。

④ここで関数が終わるわけではありません。空白行に意味はないので、コードを見やすくはできますが、コードブロックのデリミタとしては使えません。関数は次の行に進みます。

⑤forループも、コードブロックが開始した目印になります。コードブロックはインデント幅が同じであれば複数行にでも書くことができます。このforループの中には3行のコードがあります。複数行のコードブロックには特別な構文があるわけではありません。いつも通りインデントすればよいだけです。

最初はとっつきにくかったり、Fortranに似ていて嫌だと思うかもしれませんが、じきに慣れてありがたみを感じることでしょう。大きな恩恵の1つは、すべてのPythonプログラムが同じように見える、ということです。なぜなら、インデントはスタイルの問題ではなく、言語としての要求だからです。他の人が書いたPythonコードを、より簡単に読むことができます。

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

1.7. 例外


例外は、どこにでもあります。Python標準ライブラリのモジュールは、ほぼあらゆる所で例外を使っていて、Python本体もさまざまな状況で例外を出します。この本の中でも何度も見ることになります。

では、例外とは何でしょうか?通常はエラーのことで、何かがうまくいっていないことを示しています(すべての例外がエラーではありませんが、ここでは気にしないでください。)プログラム言語の中には、チェックのためにエラーを返すコードを書くことを推奨しているものもあります。Pythonでは、例外を「処理すべきものとして」使うことを推奨しています。

Pythonシェルの中でエラーが発生すると、例外の詳細と、どのように起こったかが表示されます。これは適切に処理されていない例外です。例外が出たときに、その例外はコード上では理解できず処理されていない、ということです。そのため、Pythonシェルのトップレベルまでデバッグの情報が上がって、プログラムは中断されます。シェルでは大した問題でなくても、Pythonプログラムが走っているときに例外が出たら、例外に対する処理がなければすべてのプログラムは緊急停止することになります。そうあってほしくても、そうでないにしても。

👉Javaと違って、Pythonの関数はどういう例外を出すかを宣言しません。どういう例外を捕らえるかを決めるのは、あなた自身なのです。

例外が出たとしても、プログラムを完全に壊して作り変えないといけないわけではありません。例外には対処できる場合があります。例外が正しくて、コードの中にバグがあることもあります(例:存在しない変数にアクセスしようとしていた場合など)。

予想できる例外もあります。ファイルを開いても、それが存在しないとき。モジュールをインポートしても、インストールされていないとき。データベースに接続しようとすると、接続できないとき。あるいはアクセスする正しいセキュリティ証明書を持っていないとき。例外を出す可能性のある部分を知っていれば、try...except文を使って対処できます。

👉Pythonではtry...except文を使って例外処理をしたり、raise節を使って例外を送出します。JavaとC++ではtry...catch文で例外を処理し、throw文で例外を送出します。

approximate_size()関数が出す例外は2種類です。sizeが関数側の想定より大きかったとき、またはsizeがゼロより小さかったときです。
if size < 0:
    raise ValueError('number must be non-negative')
例外を出す構文は極めてシンプルです。raise例外名 と書き、追加で説明文を書きます。この構文は関数呼び出しに似ています(実際、例外はクラスとして実装されています。このraise文はまさにValueErrorのクラスを作って'number must be non-negative'を初期化メソッドに渡します。(クラスについては7.2.章で出てきます。)

👉例外を処理するのは、例外を出す関数の中でなくても問題ありません。その関数が処理しなくても、例外は呼び出した関数に渡されて、さらにそれを呼び出した関数に渡される、というように上に積み上げられていきます。例外が全く処理されなければ、プログラムは破壊されるので、Pythonは標準エラーには”traceback”を出力して、そこで停止します。繰り返しになりますが、あなたはエラー時に停止して欲しいかもしれませんが、それはプログラム次第です。

1.7.1. インポートエラーを処理する


Pythonのビルトイン例外のひとつに、モジュールのインポートに失敗したときに出るImportErrorがあります。インポートが失敗する理由はさまざまですが、最もよくある例はモジュールがサーチパスに存在しない、というものです。これをオプション機能としてプログラムに含むことができます。例えば、chardetライブラリは文字エンコーディングを自動で検出します。このライブラリがあるなら、自分のプログラムで使いたいでしょう。しかしインストールされていなければ潔くそのまま続けることになります。これをtry...except文でやってみましょう。
try:
  import chardet
except ImportError:
  chardet = None
このようにして、chardetモジュールがあるかどうかを、シンプルなif文で確認できます。
if chardet:
  # do something
else:
  # continue anyway
ImportError例外のもう1つのよくある使い方は、2つのモジュールが共通のAPIに実装されているものの、片方だけを優先して使いたいときです(速かったりメモリ消費が少ないかもしれません)。片方のモジュールを最初にインポートしようとして失敗したとき、別のモジュールに切り替えます。例えば、XMLchapter(第12章)では、2つのモジュールが共通のElementTree.appというAPIを実装しています。最初のlxmlはサードパーティ製のモジュールで、自分でダウンロードしてインストールするものです。2番目のxml.etree.ElementTreeは、動作は遅いですが、Python3の標準ライブラリに入っています。
try:
    from lxml import etree
except ImportError:
    import xml.etree.ElementTree as etree
このtry...exceptブロックの中では、どちらのモジュールをインポートした場合も、etreeと名付けています。両方とも同じ機能のAPIを実装しているので、残りのコードはどちらのモジュールをインポートしたのかを確認し続ける必要はありません。インポートされたモジュールは常にetreeと呼ばれるので、残りのコードではif文でモジュール名を使い分けるような複雑なことにはなりません。

1.8. 紐付いていない変数


approximate_size()関数にあるこの1行をもう1度見てみましょう。
multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
変数multipleを宣言しないで、値を代入するだけです。これはPythonの仕様なので、問題ありません。値を代入していない変数の参照することは、Pythonではできません。その場合、NameError例外が送出されます。
>>> x
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'x' is not defined
>>> x = 1
>>> x
1
いつかPythonに感謝することでしょう。

1.9. すべてにおいて大文字と小文字が区別される


Python内では、名前の大文字と小文字が区別されます。変数、関数、クラス、モジュール、例外・・・すべてです。取得できるもの、定義できるもの、呼び出せるもの、生成できるもの、インポートできるもの、例外を出すもの、すべてにあてはまります。
>>> an_integer = 1
>>> an_integer
1
>>> AN_INTEGER
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'AN_INTEGER' is not defined
>>> An_Integer
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'An_Integer' is not defined
>>> an_inteGer
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'an_inteGer' is not defined

1.10. スクリプトの実行


Pythonモジュールはオブジェクトですので、便利な属性をいくつか持っています。属性を使って、自分でモジュールを書くときに簡単にテストできます。コマンドライン上でPythonファイルを走らせると実行されるような特別なコードブロックを含めるのです。humansize.pyの最後の3行を取り出してみるとこのようになります。
if __name__ == '__main__':
    print(approximate_size(1000000000000, False))
    print(approximate_size(1000000000000))
👉C言語と同じように、Pythonでは==を使って比較し、=を使って代入します。C言語とは違って、Pythonでは=を繋げて代入することはできません。そのため、比較しようとしている値以外が思いがけなく代入されることはありません。

このif文は、何が特別なのでしょうか?実は、モジュールはオブジェクトなので、すべてのモジュールはビルトイン属性の__name__を持っています。モジュールの__name__は、そのモジュールをどのように使っているかによって変わります。モジュールをインポートしたのであれば、__name__はモジュールのファイル名になります(ディレクトリパスや拡張子を含みません)。
>>> import humansize
>>> humansize.__name__
'humansize'
一方、モジュールをスタンドアロンのプログラムとして直接実行した場合は、__name__は特別な値、「__main__」をデフォルトで持っています。Pythonはこのif文を判定して、結果がTrueなのでif以下のコードブロックを実行します。この場合、2つの値をprintすることになります。
c:\home\diveintopython3> c:\python31\python.exe humansize.py
1.0 TB
931.3 GiB
以上が、はじめてのPythonプログラムです!

0 件のコメント:

コメントを投稿