単純な関数と例外処理の復習

Beginner

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

はじめに

この実験では、Python での単純な関数の定義を復習し、例外処理を探索する方法を学びます。関数は、コードを再利用可能なセグメントに構造化することを可能にする重要なプログラミング概念です。一方、例外処理は、プログラム内のエラーや予期しない状況を処理する方法です。

この実験の主な目的は、単純な関数の定義プロセスを復習し、Python での例外処理について学ぶことです。変更されるファイルは pcost.py です。

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

関数の定義

このステップでは、関数を作成する方法を学びます。Python の関数は、単一の関連するアクションを実行するために使用される、組織化された再利用可能なコードブロックです。ここでは、関数がファイルからポートフォリオデータを読み取り、総コストを計算するようにします。この関数を作成すると、異なるポートフォリオファイルで何度も使用できるため、同じコードを何度も書く手間が省けます。

問題の理解

前の実験では、ポートフォリオデータを読み取り、総コストを計算するコードを書いたかもしれません。しかし、そのコードは再利用が容易ではない書き方になっている可能性があります。今回は、そのコードを再利用可能な関数に変換します。

ポートフォリオデータファイルには特定の形式があります。これらのファイルには「シンボル 株数 価格」の形式で情報が含まれています。ファイル内の各行は株式の保有状況を表しています。たとえば、portfolio.dat という名前のファイルには、次のような行が含まれているかもしれません。

AA 100 32.20
IBM 50 91.10
...

ここで、最初の部分(「AA」や「IBM」など)は株式シンボルで、株式の一意の識別子です。2 番目の部分はその株式の保有株数で、3 番目の部分は 1 株あたりの価格です。

関数の作成

/home/labex/project ディレクトリに pcost.py という名前の Python ファイルを作成しましょう。このファイルには、私たちの関数が含まれます。以下は、pcost.py ファイルに記述するコードです。

def portfolio_cost(filename):
    """
    Computes the total cost (shares*price) of a portfolio file

    Args:
        filename: The name of the portfolio file

    Returns:
        The total cost of the portfolio as a float
    """
    total_cost = 0.0

    ## Open the file and read through each line
    with open(filename, 'r') as f:
        for line in f:
            fields = line.split()
            ## Extract the data (symbol, shares, price)
            shares = int(fields[1])
            price = float(fields[2])
            ## Add the cost to our running total
            total_cost += shares * price

    return total_cost

## Call the function with the portfolio.dat file
if __name__ == '__main__':
    cost = portfolio_cost('/home/labex/project/portfolio.dat')
    print(cost)

このコードでは、まず filename を引数とする portfolio_cost という名前の関数を定義しています。関数内では、total_cost 変数を 0.0 に初期化します。次に、open 関数を使用してファイルを読み取りモード('r')で開きます。for ループを使用して、ファイルの各行を処理します。各行について、split() メソッドを使用してフィールドに分割します。その後、株数を整数に変換し、価格を浮動小数点数に変換します。株数と価格を掛け合わせてその株式のコストを計算し、total_cost に加算します。最後に、total_cost を返します。

if __name__ == '__main__': の部分は、スクリプトが直接実行されたときに関数を呼び出すために使用されます。portfolio.dat ファイルのパスを関数に渡し、結果を出力します。

関数のテスト

では、プログラムが機能するかどうかを確認するために実行しましょう。pcost.py ファイルがあるディレクトリに移動し、Python スクリプトを実行する必要があります。以下は、そのためのコマンドです。

cd /home/labex/project
python3 pcost.py

これらのコマンドを実行すると、次のような出力が表示されるはずです。

44671.15

この出力は、ポートフォリオ内のすべての株式の総コストを表しています。

コードの理解

関数が行う処理をステップごとに分解してみましょう。

  1. filename を入力パラメータとして受け取ります。これにより、異なるポートフォリオファイルで関数を使用することができます。
  2. ファイルを開き、1 行ずつ読み取ります。これは open 関数と for ループを使用して行われます。
  3. 各行について、split() メソッドを使用してフィールドに分割します。このメソッドは、空白を基準に行を文字列のリストに分割します。
  4. 株数を整数に、価格を浮動小数点数に変換します。ファイルから読み取ったデータは文字列形式なので、算術演算を行うために変換する必要があります。
  5. 各株式のコスト(株数 * 価格)を計算し、累計に加算します。これにより、ポートフォリオの総コストが得られます。
  6. 最終的な総コストを返します。必要に応じて、この結果をプログラムの他の部分で使用することができます。

この関数は現在、再利用可能です。異なるポートフォリオファイルを指定して関数を呼び出すことで、それらのコストを計算できます。これにより、コードがより効率的で保守しやすくなります。

エラーハンドリングの追加

実際のデータを扱う際には、データの不整合やエラーに遭遇することが非常に一般的です。たとえば、データに欠損値があったり、形式が正しくなかったり、その他の問題があることがあります。Python では、このような状況を適切に処理するための例外処理メカニズムが用意されています。例外処理を使用すると、プログラムがエラーに遭遇しても突然クラッシュすることなく、実行を続けることができます。

問題の理解

portfolio3.dat ファイルを見てみましょう。このファイルには、株式シンボル、株数、1 株あたりの価格など、ポートフォリオに関するデータが含まれています。このファイルの内容を表示するには、次のコマンドを使用できます。

cat /home/labex/project/portfolio3.dat

このコマンドを実行すると、ファイル内の一部の行では、株数の部分に数字の代わりにダッシュ (-) が使われていることに気づくでしょう。以下は、見られる内容の例です。

AA 100 32.20
IBM 50 91.10
C - 53.08
...

現在のコードをこのファイルに対して実行しようとすると、プログラムはクラッシュします。その理由は、コードが株数を整数に変換しようとするのに、ダッシュ (-) を整数に変換することができないからです。コードを実行して、何が起こるか見てみましょう。

python3 -c "import sys; sys.path.append('/home/labex/project'); from pcost import portfolio_cost; print(portfolio_cost('/home/labex/project/portfolio3.dat'))"

次のようなエラーメッセージが表示されるでしょう。

ValueError: invalid literal for int() with base 10: '-'

このエラーは、Python が int(fields[1]) を実行しようとして - 文字を整数に変換できないときに発生します。

例外処理の紹介

Python の例外処理では、try ブロックと except ブロックが使用されます。try ブロックには、例外を引き起こす可能性のあるコードが含まれています。例外とは、プログラムの実行中に発生するエラーのことです。except ブロックには、try ブロック内で例外が発生した場合に実行されるコードが含まれています。

以下は、try ブロックと except ブロックがどのように動作するかの例です。

try:
    ## Code that might raise an exception
    result = risky_operation()
except ExceptionType as e:
    ## Code to handle the exception
    print(f"An error occurred: {e}")

Python が try ブロック内のコードを実行するときに例外が発生すると、実行はすぐに一致する except ブロックにジャンプします。except ブロック内の ExceptionType は、処理したい例外のタイプを指定します。変数 e には、エラーメッセージなど、例外に関する情報が含まれています。

例外処理を用いた関数の修正

pcost.py ファイルを更新して、データ内のエラーを処理できるようにしましょう。try ブロックと except ブロックを使用して、不適切なデータが含まれる行をスキップし、警告メッセージを表示します。

def portfolio_cost(filename):
    """
    Computes the total cost (shares*price) of a portfolio file
    Handles lines with bad data by skipping them and showing a warning.

    Args:
        filename: The name of the portfolio file

    Returns:
        The total cost of the portfolio as a float
    """
    total_cost = 0.0

    ## Open the file and read through each line
    with open(filename, 'r') as f:
        for line in f:
            fields = line.split()
            try:
                ## Extract the data (symbol, shares, price)
                shares = int(fields[1])
                price = float(fields[2])
                ## Add the cost to our running total
                total_cost += shares * price
            except ValueError as e:
                ## Print a warning for lines that can't be parsed
                print(f"Couldn't parse: '{line}'")
                print(f"Reason: {e}")

    return total_cost

## Call the function with the portfolio3.dat file
if __name__ == '__main__':
    cost = portfolio_cost('/home/labex/project/portfolio3.dat')
    print(cost)

この更新されたコードでは、まずファイルを開き、1 行ずつ読み取ります。各行について、フィールドに分割します。そして、株数を整数に、価格を浮動小数点数に変換しようとします。この変換が失敗した場合(つまり、ValueError が発生した場合)、警告メッセージを表示し、その行をスキップします。そうでない場合は、株式のコストを計算し、総コストに加算します。

更新された関数のテスト

では、問題のあるファイルで更新されたプログラムを実行してみましょう。まず、プロジェクトディレクトリに移動し、Python スクリプトを実行します。

cd /home/labex/project
python3 pcost.py

次のような出力が表示されるはずです。

Couldn't parse: 'C - 53.08
'
Reason: invalid literal for int() with base 10: '-'
Couldn't parse: 'DIS - 34.20
'
Reason: invalid literal for int() with base 10: '-'
44671.15

このプログラムは現在、以下のことを行います。

  1. ファイルの各行を処理しようとします。
  2. 行に無効なデータが含まれている場合、ValueError を捕捉します。
  3. 問題に関する有益なメッセージを表示します。
  4. ファイルの残りの部分の処理を続けます。
  5. 有効な行に基づいて総コストを返します。

このアプローチにより、不完全なデータを扱う際にプログラムがはるかに堅牢になります。エラーを適切に処理し、依然として有用な結果を提供することができます。

対話型実験

Python には、コードをすぐに実行できる対話型モードがあります。これは、コードのテストや新しいことの試行に非常に便利です。このステップでは、Python インタープリターから直接関数を呼び出す方法を学びます。

対話型モードで Python を実行する

Python スクリプトを実行してから対話型モードに入るには、-i フラグを使用できます。このフラグは、Python にスクリプトの実行後も対話型状態で実行を続けるよう指示します。以下はその方法です。

cd /home/labex/project
python3 -i pcost.py

このコマンドが行うことを分解してみましょう。

  1. まず、cd /home/labex/project は現在のディレクトリを /home/labex/project に変更します。ここに pcost.py スクリプトがあります。
  2. 次に、python3 -i pcost.pypcost.py スクリプトを実行します。スクリプトの実行が終了した後、Python は対話型モードのままになります。
  3. 対話型モードでは、Python コマンドを直接ターミナルに入力できます。

コマンドを実行すると、pcost.py スクリプトの出力が表示され、その後に Python プロンプト (>>>) が表示されます。このプロンプトは、Python コマンドを入力できることを示しています。

対話的に関数を呼び出す

対話型モードに入ると、portfolio_cost() 関数を異なるファイル名で呼び出すことができます。これにより、様々な入力に対する関数の動作を確認できます。以下は例です。

>>> portfolio_cost('/home/labex/project/portfolio.dat')
44671.15
>>> portfolio_cost('/home/labex/project/portfolio2.dat')
19908.75
>>> portfolio_cost('/home/labex/project/portfolio3.dat')
Couldn't parse: 'C - 53.08
'
Reason: invalid literal for int() with base 10: '-'
Couldn't parse: 'DIS - 34.20
'
Reason: invalid literal for int() with base 10: '-'
44671.15

この対話型アプローチを使用すると、以下のことができます。

  • 異なる入力で関数をテストし、期待どおりに動作するかを確認できます。
  • 様々な条件下での関数の動作を実験できます。
  • 関数呼び出しの即時結果を見ることで、コードを即座にデバッグできます。

対話型モードの利点

対話型モードにはいくつかの利点があります。

  1. 毎回全体のスクリプトを実行する必要なく、さまざまなシナリオをすばやくテストできます。
  2. 変数や式の結果をすぐに調べることができ、コード内で何が起こっているかを理解するのに役立ちます。
  3. 完全なプログラムを作成することなく、小さなコード片をテストできます。これは学習や新しいアイデアの試行に最適です。
  4. 即座にフィードバックが得られるため、Python の学習や実験に優れた方法です。

対話型モードを終了する

実験が終わったら、2 つの方法で対話型モードを終了できます。

  • exit() と入力して Enter キーを押します。これは対話型セッションを終了する簡単な方法です。
  • Ctrl+D(Unix/Linux の場合)を押します。これは対話型モードを終了するショートカットです。

Python のプログラミングの旅を通じて、関数を定義し、対話的にテストする手法は、開発とデバッグに非常に役立ちます。これにより、コードをすばやく反復し、問題を見つけて修正することができます。

まとめ

この実験では、いくつかの重要な Python プログラミングの概念を学びました。まず、コードを再利用可能にする関数の定義と使用方法を学びました。次に、プログラムの堅牢性を高める例外処理の実装を習得しました。最後に、テストや実験のために Python を対話型モードで使用する方法を発見しました。

これらのスキルは、信頼性の高い Python プログラムを書くための基礎です。関数はコードの整理と再利用に役立ち、例外処理は予期しない状況を適切に処理することを可能にし、対話型モードはテストとデバッグに強力な環境を提供します。Python の学習を進めるにつれて、これらの概念はより大規模で複雑なアプリケーションの開発にますます価値があることがわかるでしょう。