MQL5システムトレーダーの為のPython講座:第16回「関数について」

Python
スポンサーリンク
スポンサーリンク
  1. はじめに
  2. 関数とは?
  3. 関数のメリット
  4. 関数の種類
    1. 組み込み関数
      1. このコードで使用した組み込み関数
    2. ユーザー定義関数
      1. このコードで使用した部分の説明
    3. 組み込み関数とユーザー定義関数の違い
  5. 関数の定義と基本構文
    1. コードの解説
    2. 別の例:計算をする関数
    3. 引数と戻り値について
      1. 引数
      2. 戻り値
  6. 引数と戻り値
    1. 引数とは?
      1. 引数を使った関数の例
      2. この例のポイント
    2. 複数の引数
      1. 複数の引数を使った例
      2. この例のポイント
    3. 戻り値とは?
      1. 戻り値を持つ関数の例
      2. この例のポイント
    4. 引数なし・戻り値なしの関数
      1. 引数も戻り値もない関数の例
    5. 引数と戻り値の組み合わせ
  7. デフォルト引数
    1. デフォルト引数の基本的な使い方
      1. この例のポイント
    2. 複数の引数にデフォルト値を設定
    3. デフォルト引数を使う際の注意点
      1. 順序に注意
      2. デフォルト引数にオブジェクト(リストや辞書)を使う場合
    4. デフォルト引数の活用
  8. 可変長引数
    1. 可変長位置引数(*args)
      1. 基本的な例
      2. この例のポイント
    2. 可変長キーワード引数(**kwargs)
      1. 基本的な例
      2. この例のポイント
    3. 位置引数とキーワード引数の組み合わせ
      1. 順序のルール
    4. 可変長引数の活用
  9. クロージャー
    1. クロージャーの仕組み
    2. 実際の例
    3. 仕組みの説明
    4. クロージャーの応用例
      1. 状態を保持する例
    5. 注意点
  10. デコレーター
    1. デコレーターの基本的な仕組み
      1. デコレーターを使わない場合
    2. デコレーターの基本構文
      1. デコレーターを使った例
      2. 実行結果
    3. コードの解説
    4. デコレーターの応用例
      1. 例1: 実行時間を計測するデコレーター
      2. 例2: エラーハンドリングを追加するデコレーター
    5. デコレーターを使うメリット
  11. まとめ

はじめに

前回Python内包表記について学びました。

内包表記は、リストや辞書などを簡潔に記述する方法として便利なものでした。

今回の記事では、Pythonの「関数」について詳しく説明します。

関数は、コードの再利用性を高めたり、処理をわかりやすく整理するために使われる重要な仕組みです。この記事では、関数の基本的な構造や引数の使い方、さらに応用的な使い方までを解説していきます。

関数とは?

関数とは、複数の処理をひとまとめにしたもので、プログラムを効率的に書くための仕組みです。関数を使うことで、同じ処理を何度も繰り返し書く必要がなくなり、コードが見やすくなります。また、他の人がそのコードを利用する際にも便利です。

日常生活で例えると、関数は「レシピ」のようなものです。一度レシピを覚えれば、何度でも同じ料理を作ることができます。たとえば「カレーを作る」という一連の手順をまとめておき、それを呼び出すことで簡単に作業を繰り返せるというイメージです。

以下に、Pythonでの関数の基本構造を示します。

# 関数を定義します
# "def" は関数を定義するためのキーワードです
# "function_name" は関数名で、処理内容に応じたわかりやすい名前を付けます
def function_name():  # 丸括弧の中には引数(後で説明)が入ることもあります
    # 関数内で実行する処理を記述します
    print("This is a function.")  # この関数では単にメッセージを表示する処理を行います

# 定義した関数を呼び出します
# 関数名と丸括弧を使って、記述された処理を実行します
function_name()  # 実行結果として "This is a function." が表示されます

このコードでは、function_name という名前の関数を定義し、呼び出しています。

関数の定義には def キーワードを使用し、その後に関数名と丸括弧を書きます。丸括弧の中には後述する「引数」を記述する場合があります。

関数の処理内容は、必ずインデント(スペース4つ)で記述します。インデントがない場合、Pythonはエラーを出します。

関数を一度定義しておけば、何度でも繰り返し呼び出して使うことができます。この仕組みを活用すると、同じ処理を複数回書く必要がなくなるため、コードが簡潔で読みやすくなります。また、処理が変更された場合でも、関数の中身を修正するだけで、全ての呼び出しに反映されます。

次のセクションでは、関数を使うメリットについてさらに詳しく説明していきます。

関数のメリット

関数を使うことで、コードを効率化し、整理しやすくなります。ここでは、関数を使う具体的なメリットを3つ挙げて説明します。

  1. 同じ処理を繰り返し書く必要がなくなる
    • 同じ処理を別の場所で何度も使用する場合、関数としてまとめておけば、一度定義するだけで済みます。
    • 例えば、以下のコードを考えてみます。
# 同じ処理を複数回書いた場合
print("Hello, World!")  # 最初のメッセージ
print("Hello, World!")  # 2回目のメッセージ
print("Hello, World!")  # 3回目のメッセージ

このコードは、繰り返しの部分が冗長です。関数を使うと次のように書き換えることができます。

# 関数を定義して処理をまとめる
def print_hello():  # 関数名は処理内容がわかる名前にします
    print("Hello, World!")  # メッセージを表示する処理を定義

# 関数を呼び出す
print_hello()  # 1回目の呼び出し
print_hello()  # 2回目の呼び出し
print_hello()  # 3回目の呼び出し

関数を使えば、処理を一箇所にまとめられるので、コードが簡潔になります。

コードの再利用が容易になる

  • 関数を一度作れば、異なる部分でも再利用できるため、作業の効率が大幅に向上します。
  • 例えば、以下のような場合を考えます。
# 異なるメッセージを表示する関数
def print_message(message):  # 引数として表示するメッセージを受け取る
    print(message)  # メッセージを出力

# 関数を使って複数のメッセージを表示
print_message("Good morning!")  # 朝の挨拶
print_message("Good afternoon!")  # 昼の挨拶
print_message("Good evening!")  # 夜の挨拶
  1. このように、汎用的な処理を関数として定義すれば、異なるシナリオで使う際も簡単です。
  2. コードが他人にとっても理解しやすくなる
    • 関数を使うことで、コードがまとまり、読みやすくなります。例えば、長いスクリプトを複数の関数に分ければ、それぞれの関数の役割が明確になります。

関数を使うことは、プログラム全体の整理に役立ちます。次のセクションでは、関数の種類について説明します。Pythonでは、あらかじめ用意された「組み込み関数」と、自分で作る「ユーザー定義関数」の2種類が利用できます。

関数の種類

Pythonの関数には、大きく分けて「組み込み関数」と「ユーザー定義関数」の2種類があります。それぞれの特徴を詳しく説明し、初学者にもわかりやすいようにサンプルコードを用いて解説します。


組み込み関数

組み込み関数は、Pythonが最初から用意してくれている関数です。プログラムを書く際にすぐに使うことができ、特に設定やインポートは必要ありません。たとえば、データの合計を求めたり、リストの中の最大値を探したりといった処理が簡単にできます。

# 数値のリストを作成
numbers = [1, 2, 3, 4, 5]  # 数値が含まれるリストを作ります

# 合計を計算する
total = sum(numbers)  # 組み込み関数 sum() を使ってリストの合計を計算します
print(total)  # 結果: 15 が表示されます

# 最大値を探す
max_value = max(numbers)  # 組み込み関数 max() を使ってリストの中の最大値を取得します
print(max_value)  # 結果: 5 が表示されます

# 文字列の長さを測る
message = "Hello, Python!"  # 測りたい文字列を用意します
length = len(message)  # 組み込み関数 len() を使って文字列の長さを取得します
print(length)  # 結果: 14 が表示されます

このコードで使用した組み込み関数

  1. sum()
    • リストタプルの中の数値を全て足し合わせて、その合計を返します。
    • 上記の例では、リストnumbers の合計を計算しています(1 + 2 + 3 + 4 + 5 = 15)。
  2. max()
    • リストタプルの中で最も大きな値を返します。
    • 上記の例では、リストnumbers の中で最大の値(5)を取得しています。
  3. len()

これらの組み込み関数は、Pythonでよく使われる基本的な機能の一部です。特別な準備をすることなく使えるため、コードを書く際に頻繁に登場します。


ユーザー定義関数

一方、ユーザー定義関数はプログラマーが自分で作る関数です。組み込み関数では対応できない独自の処理をしたいときに利用します。

以下に、ユーザー定義関数の例を示します。

# 2つの数値を掛け算する関数を定義
def multiply(a, b):  # "a" と "b" は関数に渡す引数です
    return a * b  # 2つの引数を掛け算して結果を返します

# 定義した関数を呼び出して使う
result = multiply(3, 4)  # 3 と 4 を掛け算する
print(result)  # 結果: 12

このコードで使用した部分の説明

  1. def
    • def は関数を定義するためのキーワードです。Pythonでは、関数を作るときに必ず使用します。
  2. 関数
    • multiply という名前は、「掛け算をする関数」であることを表しています。名前は何をするかが分かりやすいものにするのが良い習慣です。
  3. return
    • 計算結果(a * b)を関数の外に返します。この値を受け取って、変数result に代入しています。

組み込み関数とユーザー定義関数の違い

特徴組み込み関数ユーザー定義関数
作成者Pythonがあらかじめ用意した関数プログラマーが自分で定義する関数
使用の準備すぐに使える使用前に定義が必要
使用例sum(), max(), len()自分の必要に応じて作成

これら2種類の関数を状況に応じて使い分けることで、効率的なプログラムを作ることができます。次のセクションでは、関数の定義方法と基本構文について詳しく説明します。引数戻り値についても解説していきます。

関数の定義と基本構文

Pythonでは、自分で関数を作ることができます。これを「関数を定義する」といいます。関数を定義すると、必要なときに呼び出して使えるようになります。

以下は、Python関数を定義する基本的な構文と、その使い方を詳しく説明します。

# 関数を定義します
# "def" は関数を定義するためのキーワード
# "say_hello" は関数名で、何をする関数なのか分かりやすく命名します
def say_hello():  # 丸括弧は、必要なら引数(後述)を受け取る部分
    # 関数の中で実行する処理を記述
    print("Hello, World!")  # この例では、単にメッセージを表示する処理

# 定義した関数を呼び出します
# 関数名と丸括弧を使って、関数の処理を実行します
say_hello()  # 出力結果: "Hello, World!"

コードの解説

  1. def キーワード
    • def は「define(定義する)」の略で、Python関数を作るときに必ず使います。
    • これがあることで、Pythonは「これから関数を作るんだな」と認識します。
  2. 関数
    • この例では関数名を say_hello としました。
    • 名前には半角英数字を使い、関数が何をするのか分かるように付けるのが良い習慣です(例: calculate_sum, print_message など)。
    • 名前にスペースは使えませんが、単語を区切りたいときはアンダースコア _ を使います。
  3. 丸括弧 ()
    • 丸括弧は、関数に「引数」を渡すときに使います。この例では引数を使わないため、空の括弧になっています。
  4. コロン :
    • 関数の処理がここから始まることを示します。
  5. インデント(スペース4つ)
    • 関数の中の処理は、必ずスペース4つ分だけ右にずらして書きます。これをインデントといいます。
    • インデントがないとエラーになるため、必ず守りましょう。
  6. print()
  7. 関数の呼び出し
    • 定義した関数を使いたいときは、関数名と丸括弧を書きます。この例では say_hello() が関数を呼び出している部分です。

別の例:計算をする関数

関数を使うと、より複雑な処理も簡潔にまとめることができます。以下は、2つの数を足し算する関数の例です。

# 足し算をする関数を定義
def add_numbers(a, b):  # 丸括弧の中に "a" と "b" という引数を指定
    # "a" と "b" を足し算して結果を返します
    return a + b  # "return" は、計算結果を関数の外に返す役割を持つキーワード

# 定義した関数を呼び出して使う
result = add_numbers(3, 5)  # 3 と 5 を引数として渡す
print(result)  # 結果: 8

引数と戻り値について

引数

  • 引数は、関数に渡すデータのことです。この例では ab引数です。
  • 関数引数を渡すことで、計算や処理の内容を柔軟に変更できます。

戻り値

  • 関数が処理を終えたあと、結果を返すものを「戻り値」といいます。
  • 上記の例では、a + b の計算結果が戻り値となり、result という変数に保存されています。

    次のセクションでは、さらに「引数を使った関数」の具体的な例と仕組みを詳しく説明します。

    引数と戻り値

    関数において「引数」と「戻り値」は非常に重要な要素です。これらを利用することで、関数は柔軟性を持ち、さまざまなデータを扱えるようになります。このセクションでは、引数戻り値の基本的な使い方とその仕組みを解説します。


    引数とは?

    引数とは、関数に渡すデータのことです。関数引数を設定すると、呼び出すたびに異なるデータを渡して処理を行うことができます。引数を使わない関数は固定された処理しかできませんが、引数を使えば同じ関数で異なるデータを処理できます。

    引数を使った関数の例

    # 引数を受け取って挨拶を表示する関数
    def greet(name):  # "name" は引数として定義されます
        print(f"Hello, {name}!")  # 引数 "name" を使ってメッセージを表示
    
    # 関数を呼び出すときに引数を渡します
    greet("Alice")  # 結果: Hello, Alice!
    greet("Bob")    # 結果: Hello, Bob!
    

    この例のポイント

    1. name は引数
      • 関数の定義部分で、丸括弧の中に指定された name が引数です。
      • 関数を呼び出すときに渡された値(”Alice” や “Bob”)が、この引数代入されます。
    2. 引数の使い方
      • 関数の中では、引数変数のように扱うことができます。この例では name を使ってメッセージを作成しています。
    3. 柔軟性
      • 同じ関数を使いながら、異なる名前で挨拶を表示できるようになっています。

    複数の引数

    関数に複数の引数を設定することもできます。これにより、関数が処理できる内容がさらに増えます。

    複数の引数を使った例

    # 2つの数値を掛け算する関数
    def multiply(a, b):  # 2つの引数 "a" と "b" を受け取ります
        print(f"{a} × {b} = {a * b}")  # 掛け算の結果を表示
    
    # 関数を呼び出す
    multiply(4, 5)  # 結果: 4 × 5 = 20
    multiply(7, 3)  # 結果: 7 × 3 = 21
    

    この例のポイント

    1. 複数の引数
      • 丸括弧内にカンマで区切って複数の引数を定義します。この例では ab の2つの引数を定義しています。
    2. 順番
      • 引数の順番は重要です。関数を呼び出す際に、渡した値は定義した順番で対応する引数代入されます。
      • 例えば、multiply(4, 5) の場合、a = 4b = 5 となります。

    戻り値とは?

    戻り値は、関数が処理を終えたあとに結果を返すものです。戻り値を利用することで、関数の結果を他の計算や処理に活用することができます。

    戻り値を持つ関数の例

    # 足し算の結果を返す関数
    def add(a, b):  # 2つの引数を受け取ります
        return a + b  # "return" で計算結果を関数の外に返します
    
    # 戻り値を受け取って変数に代入
    result = add(10, 20)  # 関数 "add" の戻り値が変数 "result" に代入されます
    print(f"The sum is: {result}")  # 結果: The sum is: 30
    

    この例のポイント

    1. return キーワード
      • return を使うと、関数の処理結果を外部に返すことができます。この例では a + b の結果を返しています。
    2. 戻り値の活用
      • 戻り値は、関数を呼び出した場所で利用できます。この例では戻り値を result に代入し、その後にメッセージとして表示しています。
    3. 関数を再利用
      • 戻り値を活用すれば、さらに複雑な計算や処理の部品として関数を利用することができます。

    引数なし・戻り値なしの関数

    引数戻り値もない関数も作ることができます。単純に処理を実行するだけの場合に使用します。

    引数も戻り値もない関数の例

    # 挨拶を表示するだけの関数
    def say_hello():
        print("Hello, World!")
    
    # 呼び出すだけで処理が実行されます
    say_hello()  # 結果: Hello, World!
    

    引数と戻り値の組み合わせ

    引数戻り値を組み合わせることで、関数の柔軟性がさらに高まります。関数の設計に合わせてこれらを使い分けましょう。

    次のセクションでは、引数をさらに詳しく掘り下げ、デフォルト値や柔軟な引数の使い方について説明します。

    デフォルト引数

    Pythonでは、関数を定義する際に引数にデフォルト値を設定することができます。デフォルト引数を使うと、関数を呼び出すときに値を渡さなくても、自動的にデフォルト値が使われます。これにより、引数を省略して関数を呼び出せる柔軟な設計が可能になります。


    デフォルト引数の基本的な使い方

    以下は、デフォルト引数を設定した関数の例です。

    # デフォルト引数を持つ関数
    def greet(name="Guest"):  # 引数 "name" にデフォルト値 "Guest" を設定
        print(f"Hello, {name}!")  # 引数 "name" を使って挨拶メッセージを表示
    
    # 引数を省略して関数を呼び出す
    greet()  # 結果: Hello, Guest!
    
    # 引数を指定して関数を呼び出す
    greet("Alice")  # 結果: Hello, Alice!
    

    この例のポイント

    1. デフォルト値の指定
      • 関数定義時に、引数名の後に = を使ってデフォルト値を指定します。
      • この例では、name にデフォルト値として “Guest” を設定しています。
    2. 引数を省略
      • 引数を渡さずに関数を呼び出すと、デフォルト値が自動的に使われます。
      • 例: greet() の場合、name は “Guest” として扱われます。
    3. 引数の指定
      • 引数を渡して関数を呼び出すと、その値がデフォルト値を上書きします。
      • 例: greet(“Alice”) の場合、name は "Alice" になります。

    複数の引数にデフォルト値を設定

    複数の引数を持つ関数にも、それぞれデフォルト値を設定することができます。

    # 複数の引数にデフォルト値を設定
    def introduce(name="Unknown", age=0):  # "name" と "age" にデフォルト値を設定
        print(f"My name is {name} and I am {age} years old.")
    
    # 引数を省略して関数を呼び出す
    introduce()  # 結果: My name is Unknown and I am 0 years old.
    
    # 1つだけ引数を指定して関数を呼び出す
    introduce("Alice")  # 結果: My name is Alice and I am 0 years old.
    
    # 両方の引数を指定して関数を呼び出す
    introduce("Bob", 25)  # 結果: My name is Bob and I am 25 years old.
    

    デフォルト引数を使う際の注意点

    順序に注意

    デフォルト値を持つ引数は、デフォルト値を持たない引数の後に記述する必要があります。そうでないとエラーになります。

    # 正しい例
    def correct_example(a, b=10):
        return a + b
    
    # エラーが発生する例
    # デフォルト値を持つ引数が先にあるとエラーになります
    # def incorrect_example(a=10, b):
    #     return a + b
    

    デフォルト引数にオブジェクト(リストや辞書)を使う場合

    デフォルト引数リストや辞書のような「可変オブジェクト」を使うと、予期せぬ動作をすることがあります。

    # デフォルト引数にリストを使った例
    def append_to_list(value, my_list=[]):  # デフォルト引数に空のリストを設定
        my_list.append(value)  # 引数 "value" をリストに追加
        return my_list
    
    # 呼び出し1回目
    print(append_to_list(1))  # 結果: [1]
    
    # 呼び出し2回目
    print(append_to_list(2))  # 結果: [1, 2] 予期せぬ動作:リストが共有されている
    

    この問題を防ぐには、デフォルト引数に None を使い、内部で初期化する方法を用います。

    # リストを安全に扱う方法
    def append_to_list_safe(value, my_list=None):  # デフォルト引数を None に設定
        if my_list is None:  # 引数 "my_list" が None の場合、新しいリストを作成
            my_list = []
        my_list.append(value)
        return my_list
    
    # 呼び出し1回目
    print(append_to_list_safe(1))  # 結果: [1]
    
    # 呼び出し2回目
    print(append_to_list_safe(2))  # 結果: [2] 問題が解消される
    

    デフォルト引数の活用

    デフォルト引数をうまく使えば、関数を呼び出す際の手間を省けるだけでなく、処理を柔軟にカスタマイズすることが可能です。次のセクションでは、さらに柔軟な引数の使い方として「可変長引数」を紹介します。これにより、引数の数が決まっていない場合でも対応できるようになります。

    可変長引数

    Pythonでは、関数に渡す引数の数が事前に決まっていない場合に可変長引数」を使うことができます。可変長引数には「位置引数」を扱う方法と「キーワード引数」を扱う方法の2種類があります。それぞれの使い方を詳しく説明します。


    可変長位置引数(*args)

    可変長位置引数は、関数に渡された複数の位置引数をまとめてタプルとして受け取る方法です。引数の数が決まっていない場合に便利です。

    基本的な例

    # 可変長位置引数を使った関数
    def sum_numbers(*args):  # アスタリスク "*" を付けた "args" が可変長位置引数
        return sum(args)  # 引数として受け取ったタプルの合計を計算
    
    # 関数を呼び出して複数の引数を渡す
    print(sum_numbers(1, 2, 3))  # 結果: 6
    print(sum_numbers(10, 20))   # 結果: 30
    print(sum_numbers())         # 結果: 0(引数なしの場合は合計が 0)
    

    この例のポイント

    1. *args
      • *args は、関数が複数の位置引数を受け取る場合に使用します。
      • 引数タプルとして関数内に渡されます。この例では、(1, 2, 3) や (10, 20) などがタプルとして扱われます。
    2. 柔軟性
      • 引数の数が決まっていない場合に対応でき、必要な数だけ引数を渡せます。
    3. タプルとして操作
      • 受け取った引数タプルなので、sum() やループ処理などを使って柔軟に操作できます。

    可変長キーワード引数(**kwargs)

    可変長キーワード引数は、関数に渡された複数のキーワード引数を辞書として受け取る方法です。キーワード引数とは、key=value の形式で渡される引数のことです。

    基本的な例

    # 可変長キーワード引数を使った関数
    def print_info(**kwargs):  # アスタリスク2つ "**" を付けた "kwargs" が可変長キーワード引数
        for key, value in kwargs.items():  # 辞書のキーと値をループで取得
            print(f"{key}: {value}")  # キーと値を出力
    
    # 関数を呼び出して複数のキーワード引数を渡す
    print_info(name="Alice", age=25, city="Tokyo")
    # 出力:
    # name: Alice
    # age: 25
    # city: Tokyo
    

    この例のポイント

    1. **kwargs
      • **kwargs は、関数が複数のキーワード引数を受け取る場合に使用します。
      • 引数は辞書として関数内に渡されます。この例では、{"name": "Alice", "age": 25, "city": "Tokyo"} のような辞書です。
    2. 柔軟性
      • キーワード引数の数が決まっていない場合に対応できます。必要なキーと値を好きなだけ渡せます。
    3. 辞書として操作
      • 受け取った引数は辞書として操作可能です。ループやキーの直接参照を使って処理できます。

    位置引数とキーワード引数の組み合わせ

    位置引数とキーワード引数を組み合わせて使うこともできます。ただし、順序には注意が必要です。

    # 位置引数とキーワード引数の組み合わせ
    def display_info(name, *args, **kwargs):
        print(f"Name: {name}")  # 位置引数 "name" を表示
        print("Other Info:", args)  # 可変長位置引数 "args" を表示
        print("Details:", kwargs)  # 可変長キーワード引数 "kwargs" を表示
    
    # 関数を呼び出して引数を渡す
    display_info(
        "Alice",  # 最初の位置引数
        25, "Tokyo",  # 可変長位置引数
        job="Engineer", hobby="Reading"  # 可変長キーワード引数
    )
    # 出力:
    # Name: Alice
    # Other Info: (25, 'Tokyo')
    # Details: {'job': 'Engineer', 'hobby': 'Reading'}
    

    順序のルール


    可変長引数の活用

    可変長引数を使えば、柔軟性の高い関数を作ることができます。例えば、ログ出力やデータの集計、動的な設定などに役立ちます。

    クロージャー

    クロージャーを簡単に説明すると、「関数の中で作られた関数が、その外側の関数で使われていた変数を覚えている状態」のことです。これを使うと、データを保持したまま動作する特別な関数を作ることができます。


    クロージャーの仕組み

    クロージャーを理解するために、次のポイントを押さえておきましょう。

    1. 関数の中で別の関数を定義する(関数関数)。
    2. 内側の関数(子関数)が外側の関数(親関数)の変数を使う。
    3. 関数が終了した後でも、子関数がその変数を覚えている。

    実際の例

    以下は、クロージャーを使った例です。

    # クロージャーの例
    def make_multiplier(factor):  # 外側の関数。掛け算の倍率を受け取ります
        def multiplier(number):  # 内側の関数。掛け算をする処理を定義します
            return number * factor  # 内側の関数で外側の変数 "factor" を使用
        return multiplier  # 内側の関数を返します
    
    # 外側の関数を使って特定の倍率の関数を作成
    double = make_multiplier(2)  # 2倍する関数を作成
    triple = make_multiplier(3)  # 3倍する関数を作成
    
    # 作成した関数を使って計算
    print(double(5))  # 結果: 10 (5 × 2)
    print(triple(5))  # 結果: 15 (5 × 3)
    

    仕組みの説明

    このコードの流れを詳しく解説します。

    1. 外側の関数 make_multiplier
      • この関数引数factor を受け取り、それを使って特定の倍率で掛け算をする「内側の関数」を作ります。
    2. 内側の関数 multiplier
      • 内側の関数は、外側の関数引数factor を使用しています。
      • この関数は、掛け算をする処理を行います。
    3. 関数を返す
      • 外側の関数 make_multiplier は、内側の関数 multiplier を返します。
      • これにより、外側の関数が終了しても、内側の関数factor の値を覚えています。
    4. 新しい関数を作成
      • make_multiplier(2) を呼び出すと、「2倍する関数」が作成されます。
      • 同様に、make_multiplier(3) を呼び出すと、「3倍する関数」が作成されます。
    5. データを保持する
      • 作成された関数 double と triple は、それぞれの factor の値を覚えています。
      • 例えば、double(5) を呼び出すと、factor2 の状態で動作します。

    クロージャーの応用例

    クロージャーは、以下のような場面で役立ちます。

    1. データをカプセル化する
      • 外部から直接アクセスさせたくないデータをクロージャーの中に隠すことができます。
    2. 状態を保持する関数

    状態を保持する例

    # 状態を保持するクロージャー
    def counter():
        count = 0  # 外側の関数の変数。初期値は 0。
    
        def increment():  # 内側の関数
            nonlocal count  # 外側の変数 "count" を使用する
            count += 1  # カウントを1増やす
            return count  # 現在のカウントを返す
    
        return increment  # 内側の関数を返す
    
    # カウンター関数を作成
    counter1 = counter()  # 1つ目のカウンター
    counter2 = counter()  # 2つ目のカウンター
    
    # カウントを増やす
    print(counter1())  # 結果: 1
    print(counter1())  # 結果: 2
    print(counter2())  # 結果: 1 (別のカウンターなので独立)
    print(counter2())  # 結果: 2
    

    注意点

    1. nonlocal キーワード
      • 内側の関数から外側の関数変数を変更する場合、nonlocal を使う必要があります。(nonlocalについてはこの後、別の講座記事で解説予定です)
    2. クロージャーは内側の関数を返す

    クロージャーは、データを保持したり状態を管理したりするために非常に便利な仕組みです。理解が難しい場合は、上記の例を何度か動かして試してみてください。次のセクションでは、さらに発展的な内容として「デコレーター」を紹介します。デコレーターは、関数に特定の機能を追加する際に使われる重要なテクニックです。

    デコレーター

    デコレーターは、関数に特定の機能を追加したり、その振る舞いを変更したりするための仕組みです。プログラムを書き直すことなく、関数の前後に処理を挿入したり、動作を修飾したりできる便利な方法です。

    デコレーターを使うと、コードがシンプルで読みやすくなるため、Pythonプログラミングにおいてよく使われます。


    デコレーターの基本的な仕組み

    デコレーターは、「他の関数引数として受け取る関数」です。この関数の中で、元の関数に何らかの処理を追加したり、修飾したりします。

    デコレーターを使わない場合

    まず、デコレーターを使わない場合の例を見てみましょう。関数の前後に特定の処理を追加する例です。

    # 特定の処理を追加する関数
    def my_function():  # 元の関数
        print("This is the main function.")  # 本来の処理
    
    # 元の関数を呼び出す前後に処理を追加
    print("Start of the function.")  # 前処理
    my_function()  # 関数の実行
    print("End of the function.")  # 後処理
    

    このコードでは、関数 my_function を呼び出す前後に「開始」と「終了」を示すメッセージを表示しています。しかし、この方法では毎回 print 文を手動で追加する必要があります。これをデコレーターを使って解決します。


    デコレーターの基本構文

    デコレーターを使うと、先ほどの例をより簡潔に記述できます。

    デコレーターを使った例

    # デコレーターを定義
    def decorator_function(original_function):  # 他の関数を引数として受け取る
        def wrapper_function():  # 元の関数を修飾する新しい関数
            print("Start of the function.")  # 前処理
            original_function()  # 元の関数を実行
            print("End of the function.")  # 後処理
        return wrapper_function  # 修飾した関数を返す
    
    # デコレーターを適用
    @decorator_function  # "my_function" に "decorator_function" を適用
    def my_function():  # 元の関数
        print("This is the main function.")  # 本来の処理
    
    # 関数を呼び出す
    my_function()
    

    実行結果

    Start of the function.
    This is the main function.
    End of the function.
    

    コードの解説

    1. デコレーターの定義
    2. ラッパー関数(wrapper_function)
      • ラッパー関数とは、元の関数の動作を修飾するために作成される関数です。
      • この例では、wrapper_function が元の関数の実行前後に追加の処理を挿入しています。
    3. @ 記法
    4. 元の関数の実行
      • ラッパー関数の中で original_function() を呼び出すことで、元の関数をそのまま実行しています。

    デコレーターの応用例

    デコレーターは、ログ出力やエラーハンドリングなど、さまざまな場面で役立ちます。ここでは、いくつかの実用例を紹介します。

    例1: 実行時間を計測するデコレーター

    import time  # 実行時間を計測するために必要
    
    # 実行時間を計測するデコレーター
    def timing_decorator(func):
        def wrapper():
            start_time = time.time()  # 開始時刻を記録
            func()  # 元の関数を実行
            end_time = time.time()  # 終了時刻を記録
            print(f"Execution time: {end_time - start_time} seconds")  # 実行時間を表示
        return wrapper
    
    # デコレーターを適用
    @timing_decorator
    def sample_function():
        for _ in range(1000000):  # 簡単な処理を実行
            pass
    
    # 関数を呼び出す
    sample_function()
    

    例2: エラーハンドリングを追加するデコレーター

    # エラーをキャッチしてメッセージを表示するデコレーター
    def error_handling_decorator(func):
        def wrapper(*args, **kwargs):  # 可変長引数でどんな関数にも対応
            try:
                func(*args, **kwargs)  # 元の関数を実行
            except Exception as e:  # エラーが発生した場合
                print(f"An error occurred: {e}")  # エラーメッセージを表示
        return wrapper
    
    # デコレーターを適用
    @error_handling_decorator
    def divide(a, b):
        print(a / b)  # 割り算を実行
    
    # 正常な実行
    divide(10, 2)  # 結果: 5.0
    
    # エラーが発生する場合
    divide(10, 0)  # 結果: An error occurred: division by zero
    

    デコレーターを使うメリット

    1. コードの再利用
    2. コードの可読性
      • 関数に追加の処理があることが @decorator 記法で一目瞭然になります。
    3. 保守性
      • 元の関数を直接変更することなく、新しい機能を追加できます。

    デコレーターは、Pythonの柔軟性を活かした強力な仕組みです。最初は少し複雑に感じるかもしれませんが、例を何度も試して理解を深めてみてください。次のセクションでは、関数のさらなる応用例として「関数関数」を詳しく解説していきます。

    まとめ

    この記事では、Python関数について詳しく解説しました。関数の基本的な定義方法から、引数戻り値デフォルト引数可変長引数クロージャーデコレーターまで幅広く扱いました。これらの仕組みを理解し活用することで、コードの再利用性や可読性が向上し、より効率的なプログラミングが可能になります。

    関数Pythonを学ぶ上で欠かせない重要な要素です。まずは基本的な関数の使い方に慣れ、応用例を試しながらステップアップしていきましょう。

    MQL5システムトレーダーの為のPython講座:第15回「内包表記について」

    タイトルとURLをコピーしました