Python スクリプト作成の練習

Intermediate

This tutorial is from open-source community. Access the source code

はじめに

このパートでは、Python スクリプトを書く実践について、もっと詳しく見ていきます。

これは Guided Lab です。学習と実践を支援するためのステップバイステップの指示を提供します。各ステップを完了し、実践的な経験を積むために、指示に注意深く従ってください。過去のデータによると、この 中級 レベルの実験の完了率は 56%です。学習者から 100% の好評価を得ています。

スクリプトとは?

「スクリプト」とは、一連の文を実行してから停止するプログラムのことです。

## program.py

statement1
statement2
statement3
...

これまで主にスクリプトを書いてきました。

問題

便利なスクリプトを書くと、機能や機能性が増えていきます。他の関連する問題に適用したい場合もあるでしょう。時間が経つにつれて、重要なアプリケーションになるかもしれません。そして、注意を怠らなければ、巨大な混乱の山になってしまうかもしれません。ですから、整理をしましょう。

定義

名前は、後で使用される前に必ず定義する必要があります。

def square(x):
    return x*x

a = 42
b = a + 2     ## `a` が定義されていることが必要です

z = square(b) ## `square` と `b` が定義されていることが必要です

順序は重要です。 ほとんどの場合、変数や関数の定義を一番上に近付けます。

関数の定義

単一の「タスク」に関連するコードをすべて一箇所にまとめるのは良い考えです。関数を使いましょう。

def read_prices(filename):
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

関数はまた、繰り返しの操作を簡略化します。

oldprices = read_prices('oldprices.csv')
newprices = read_prices('newprices.csv')

関数とは?

関数は、名前付きの文のシーケンスです。

def funcname(args):
  statement
  statement
...
  return result

内部では、Python の「任意の」文を使用できます。

def foo():
    import math
    print(math.sqrt(2))
    help(math)

Python には特別な文はありません(覚えやすいです)。

関数の定義

関数は、どんな順序でも「定義」できます。

def foo(x):
    bar(x)

def bar(x):
    statements

## または
def bar(x):
    statements

def foo(x):
    bar(x)

関数は、プログラム実行中に実際に「使用」(または呼び出し)される前にのみ定義する必要があります。

foo(3)        ## foo は既に定義されている必要があります

スタイリッシュには、関数が「下から上」の形式で定義されるのが一般的です。

下から上のスタイル

関数は構築ブロックとして扱われます。小さくて単純なブロックが先に来ます。

## myprogram.py
def foo(x):
 ...

def bar(x):
 ...
    foo(x)          ## 上で定義されています
 ...

def spam(x):
 ...
    bar(x)          ## 上で定義されています
 ...

spam(42)            ## 関数を使用するコードは最後に現れます

後の関数は前の関数をベースに構築されます。再び、これはただのスタイルの問題です。上記のプログラムで重要なのは、spam(42) の呼び出しが最後に来ることだけです。

関数の設計

理想的には、関数は「ブラックボックス」であるべきです。関数は渡された入力のみで動作し、グローバル変数や不可解な副作用を避けるべきです。主な目標は、「モジュール性」と「予測可能性」です。

ドキュメント文字列

関数のドキュメント文字列を含めるのは良い慣例です。ドキュメント文字列は、関数名の直後に書かれる文字列です。これらは help()、統合開発環境(IDE)、その他のツールに提供されます。

def read_prices(filename):
    '''
    Read prices from a CSV file of name,price data
    '''
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

ドキュメント文字列の良い慣例としては、関数が何を行うかを 1 文で簡潔にまとめることです。もっと詳細な情報が必要な場合は、使用例の短いサンプルと引数のより詳細な説明を含めてください。

型アノテーション

関数定義にオプショナルな型ヒントを追加することもできます。

def read_prices(filename: str) -> dict:
    '''
    Read prices from a CSV file of name,price data
    '''
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

これらのヒントは実際の動作には何も影響しません。純粋に情報提供のみを目的としています。ただし、統合開発環境(IDE)、コードチェッカー、その他のツールでは、これらのヒントを利用してさらに多くのことを行うことができます。

第 2 節では、株式ポートフォリオのパフォーマンスを示すレポートを出力する report.py というプログラムを作成しました。このプログラムはいくつかの関数で構成されていました。たとえば:

## report.py
import csv

def read_portfolio(filename):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and price.
    '''
    portfolio = []
    with open(filename) as f:
        rows = csv.reader(f)
        headers = next(rows)

        for row in rows:
            record = dict(zip(headers, row))
            stock = {
                'name' : record['name'],
               'shares' : int(record['shares']),
                'price' : float(record['price'])
            }
            portfolio.append(stock)
    return portfolio
...

ただし、プログラムには一連の手順通りの計算のみを行う部分もありました。このコードはプログラムの後半に現れました。たとえば:

...

## Output the report

headers = ('Name', 'Shares', 'Price', 'Change')
print('%10s %10s %10s %10s'  % headers)
print(('-' * 10 +'') * len(headers))
for row in report:
    print('%10s %10d %10.2f %10.2f' % row)
...

この演習では、このプログラムを取り上げて、関数の使用を中心にもう少し強力に整理します。

演習 3.1:関数のコレクションとしてプログラムを構造化する

report.py プログラムを変更して、計算や出力を含むすべての主要な操作を関数のコレクションによって行うようにします。具体的には:

  • レポートを出力する print_report(report) 関数を作成します。
  • プログラムの最後の部分を変更して、関数呼び出しのシリーズ以外は何も計算しないようにします。

演習 3.2:プログラム実行用のトップレベル関数の作成

プログラムの最後の部分を取り出して、単一の関数 portfolio_report(portfolio_filename, prices_filename) にまとめます。この関数は、次の関数呼び出しが以前と同じようにレポートを作成するように動作するようにします。

portfolio_report('/home/labex/project/portfolio.csv', '/home/labex/project/prices.csv')

この最終バージョンでは、プログラムは一連の関数定義の後に、最後に単一の関数呼び出し portfolio_report() だけになります(これがプログラムに含まれるすべてのステップを実行します)。

プログラムを単一の関数に変換することで、異なる入力で実行することが簡単になります。たとえば、プログラムを実行した後に対話的に次の文を試してみてください。

>>> portfolio_report('/home/labex/project/portfolio2.csv', '/home/labex/project/prices.csv')
... 出力を見る...
>>> files = ['/home/labex/project/portfolio.csv', '/home/labex/project/portfolio2.csv']
>>> for name in files:
        print(f'{name:-^43s}')
        portfolio_report(name, '/home/labex/project/prices.csv')
        print()

... 出力を見る...
>>>

解説

Python を使えば、文のシーケンスが記述された単一のファイルにすぎない比較的非構造化なスクリプトコードを書くことが非常に簡単です。全体的に見ると、できる限り関数を活用する方がほとんどの場合良いでしょう。いつかそのスクリプトが増えて、もう少し整理されていることを望むようになるでしょう。また、少々知られていない事実ですが、関数を使うと Python の実行速度が少し速くなります。

まとめ

おめでとうございます!あなたはスクリプティングの実験を完了しました。あなたの技術を向上させるために、LabEx でさらに多くの実験を行って練習することができます。