Python School 2.0.0 documentation

スクリプトファイルの構成

«  トイプログラム - FizzBuzz   ::   Contents   ::   CSV ファイルの処理方法  »

スクリプトファイルの構成

Python はモジュールのトップレベルから記述を開始できますが、 だらだらと書き進めてしまうと可読性が低くなります。 基本的な構成を統一することでソースコードを共有しやすい状態にしましょう。

前のセクション (トイプログラム - FizzBuzz) からは、次の部分を共通項として抽出できます。

main 関数

C言語や Java のように、処理を開始する手続きは main() 関数として独立させましょう。 これは慣習の面と、実際的な面の両方で有用です。 たとえば、Google App Engine の場合は以下のリンクで説明されています。

main() を作ったら test() も作るようにしてください。 実際に必要な処理と実験的な処理は分離しましょう。 実装とテストケースを平行して実装することで、 print デバッグからの脱却にも役立ちます。

コマンドライン引数

コマンドライン引数はオプションと実引数から構成されます。 オプションはハイフンから始まる文字列で、ハイフンが1つの場合はショートオプション、2つの場合はロングオプションと呼ばれます。 また、値を取るオプションと取らないオプションもあります。 詳しくは Unix 系のコマンドを調べてください。

Python でコマンドライン引数を扱う場合は標準モジュールの argparse を使います。 Python 2.4 系もサポートする場合は optparse を使うことになりますが、その局面は多くないでしょう。

サードパーティーのライブラリとしては docoptgflags が実際的だと考えられます。 docopt はドキュメントも一緒に書けること、Python 以外のプログラム言語(例えば Go)への移植が容易なことがメリットです。 gflags は複数のモジュールからなるスクリプトを開発する場合に有用です。 その他、Django や Twisted などのフレームワークを利用する場合はオプションライブラリが同梱されています。

  • docopt - docopt.org - Command-line interface description language
  • python-gflags - code.google.com (更新は止まっています)

オプションの処理

コマンドラインスクリプトの場合は、以下の引数をオプションで制御できないかを検討してください。

  • help - スクリプトの使い方を表示する
  • version - スクリプトのバージョンを表示する
  • verbosity - ログ出力の冗長性を高くする
  • quiet - ログ出力の冗長性を低くする
  • force - 何が何でも実行させる
  • dryrun - 実際には実行しない
  • configuration - 設定ファイルを指定する

自動プログラミング

フルスクラッチでソースコードを記述するのではなく、 何らかの雛型 / スニペットからソースコードを記述するクセを付けましょう。

雛型を共有しておくことにより、エンコーディングの間違いは減少し、 コマンドライン引数に関する最低限のルールは守られます。 また、主要な処理を main 関数に閉じ込めておくことができますので、 スクリプトの再利用性が高まります。

もちろん、パッケージを共有することでもこれらは改善できます。 基本的な記述に時間をかけることなく、関心の高い部分の実装に時間をかけられることが大切です。

宿題

自分用のスクリプトテンプレートを用意してください。

以降の章では次の3つを前提として進めます。

  • if __name__ == '__main__': で main 関数を呼び出す。
  • main 関数から個別の処理を呼び出し、個別の処理は test からも確認可能にする。
  • main 関数の最初で引数を処理する。

例 (boilerplate.py)

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""%prog [options] args
"""

import argparse
import logging


def parse_args():
    """Parse arguments and set up logging verbosity.

    :rtype: parsed arguments as Namespace object.
    """
    parser = argparse.ArgumentParser(__doc__)
    parser.add_argument("-f", "--file", dest="filename",
                        help="setting file", metavar="FILE")
    parser.add_argument("-o", "--output", dest="output",
                        help="output file", metavar="FILE")
    parser.add_argument("-n", "--dryrun", dest="dryrun",
                        help="dry run", default=False, action="store_true")
    parser.add_argument("-v", "--verbose", dest="verbose", default=False,
                        action="store_true", help="verbose mode")
    parser.add_argument("-q", "--quiet", dest="quiet", default=False,
                        action="store_true", help="quiet mode")

    args = parser.parse_args()

    if args.verbose:
        logging.basicConfig(level=logging.DEBUG)
    elif not args.quiet:
        logging.basicConfig(level=logging.INFO)

    return args


def process(args):
    """Main procedure with some tests.
    """
    pass


def main():
    args = parse_args()
    process(args)


def test():
    pass

if __name__ == '__main__':
    main()

# vim: set et ts=4 sw=4 cindent fileencoding=utf-8 :

«  トイプログラム - FizzBuzz   ::   Contents   ::   CSV ファイルの処理方法  »