Python におけるラムダ関数

PythonBeginner
オンラインで実践に進む

はじめに

この実験(Lab)では、Python におけるラムダ関数(lambda functions)の使い方を学びます。まず、無名関数(anonymous functions)の概念と lambda キーワードについて理解し、従来の関数定義との比較を行います。その後、さまざまな数の引数を持つ単純なラムダ関数を作成します。

さらに、この実験では、sorted のような Python の組み込み関数とラムダ関数を効果的に使用する方法を探ります。最後に、コードの可読性と保守性を確保するためにラムダ関数を使用する際のベストプラクティスについて議論します。

無名関数と Lambda の理解

このステップでは、Python における無名関数の概念を紹介し、特に lambda キーワードに焦点を当てます。無名関数とは名前のない関数であり、単純な単一式の関数を簡潔に定義する方法を提供します。

通常、Python では def キーワードを使用して関数を定義します。例えば、数値を 2 倍にする関数は次のようになります。

def double(x):
    return x * 2

print(double(10))

このような小さな関数に対しては、lambda はよりコンパクトな構文を提供します。同じ関数を lambda を使用して作成してみましょう。

左側の WebIDE ファイルエクスプローラーで、ファイル ~/project/lambda_example1.py を見つけて開きます。以下のコードをファイルに追加してください。

## Define a lambda function to double a number
double_lambda = lambda x: x * 2

## Call the lambda function and print the result
print(double_lambda(10))

構文は lambda 引数: 式 です。引数 は入力であり、 は評価されて返される単一の操作です。return キーワードがないことに注意してください。戻り値は暗黙的です。

ファイルを保存します。スクリプトを実行するには、WebIDE でターミナルを開き、次のコマンドを実行します。

python3 ~/project/lambda_example1.py

ターミナルに結果が出力されるはずです。

20

これにより、ラムダ関数を変数に割り当て、通常の関数と同じように呼び出すことができることが示されました。

多様な引数を持つラムダ関数の作成

ラムダ関数は柔軟性があり、引数なし、1 つ、または複数の引数を持つように定義できます。ただし、常に単一の式に限定されます。このステップでは、異なる数の引数を持つラムダの作成を探ります。

まず、引数を取らないラムダ関数を作成してみましょう。これは、定数や単純で反復可能なアクションを定義する場合に役立ちます。

ファイルエクスプローラーからファイル ~/project/lambda_example2.py を開きます。以下のコードを追加してください。

## Define a lambda function with no arguments
get_greeting = lambda: "Hello, World!"

## Call the lambda function and print the result
print(get_greeting())

次に、複数の引数を受け取るラムダ関数を作成します。2 つの数値を加算するラムダを定義します。このコードを同じ lambda_example2.py ファイルに追加してください。

## Define a lambda function that adds two numbers
add_numbers = lambda x, y: x + y

## Call the lambda function with two arguments and print the result
print(add_numbers(5, 3))

ファイルを保存します。次に、ターミナルからスクリプトを実行して、両方の出力を確認します。

python3 ~/project/lambda_example2.py

ターミナルには、両方のラムダ関数の結果が表示されます。

Hello, World!
8

これにより、ラムダ関数が異なる引数の構成を処理でき、さまざまな単純なタスクに対して多用途であることを示しています。

sorted() 関数でのラムダの使用

ラムダ関数の最も一般的なユースケースの 1 つは、高階関数(他の関数を引数として受け取る関数)のための、迅速なインライン関数として機能することです。代表的な例が Python の組み込み関数 sorted() であり、これは key 引数を受け取ることができます。key は、ソート比較を行う前に各要素に対して呼び出される関数を指定します。

各タプルが製品とその価格を表すタプルのリストがあると想像してください。このリストを価格に基づいてソートしたいとします。

エディタでファイル ~/project/lambda_sorted.py を開きます。以下のコードを追加してください。

## A list of tuples (product, price)
products = [('Laptop', 1200), ('Mouse', 25), ('Keyboard', 75)]

## Sort the list by price (the second element of each tuple) using a lambda function
sorted_products = sorted(products, key=lambda item: item[1])

## Print the sorted list
print(sorted_products)

このコードでは、key=lambda item: item[1]sorted() に対し、各タプルの 2 番目の要素(item[1]、つまり価格)をソートのための値として使用するように指示しています。これは、def を使用して別の関数を定義するよりもはるかに簡潔です。

ファイルを保存し、ターミナルから実行します。

python3 ~/project/lambda_sorted.py

製品のリストが価格の昇順でソートされて表示されます。

[('Mouse', 25), ('Keyboard', 75), ('Laptop', 1200)]

このパターンは非常に一般的であり、複雑なデータ構造をシンプルで読みやすい方法でソートするのに役立ちます。

高度なラムダテクニック

このステップでは、ラムダ関数の使用法について、デフォルトの引数値の設定や、ラムダ関数の即時実行(Immediately Invoked)など、より高度な方法を探ります。

通常の関数と同様に、ラムダ関数にもデフォルト値を持つ引数を設定できます。これにより、関数呼び出し時に引数が提供されなかった場合のフォールバック値が提供されます。

エディタでファイル ~/project/lambda_advanced.py を開きます。以下のコードを追加してください。

## Define a lambda function with a default parameter value
power = lambda base, exponent=2: base ** exponent

## Call the lambda function without the optional argument (uses default)
print(power(3))

## Call the lambda function with both arguments
print(power(3, 3))

もう一つの興味深いテクニックは、ラムダ関数を定義して即座に呼び出すことです。これは即時実行関数式(IIFE: Immediately Invoked Function Expression)として知られています。これは、名前空間を汚染することなく値を計算するために、一時的な一度限りの関数を作成するのに役立ちます。

以下のコードを lambda_advanced.py ファイルに追加してください。

## Define and immediately invoke a lambda function to calculate a discounted price
price = 100
discount_percentage = 20
final_price = (lambda p, d: p * (1 - d / 100))(price, discount_percentage)

print(final_price)

ファイルを保存し、ターミナルから実行します。

python3 ~/project/lambda_advanced.py

出力には、両方の例の結果が表示されます。

9
27
80.0

これらのテクニックはラムダの柔軟性を示していますが、可読性が最も重要であることを忘れないでください。ロジックが複雑になる場合は、標準の def 関数の方が適切な選択となることがよくあります。

ベストプラクティスと可読性

この最終ステップでは、ラムダ関数の使用に関するベストプラクティスについて議論します。ラムダはコードを簡潔に記述するための強力なツールですが、可読性と保守性を維持するために慎重に使用する必要があります。

ラムダを使用すべき場合:

  • 高階関数の引数として: これが主なユースケースです。sorted()map()filter() のような関数は、ラムダの理想的な候補です。
  • 単純で短い操作: ロジックが 1 行に無理なく明確に収まる場合は、ラムダが良い選択です。

ラムダを避けるべき場合:

  • 複雑なロジック: 複数のステートメント、複雑な条件ロジック、またはループが必要な場合は、必ず def 関数を使用してください。
  • 可読性の懸念: ラムダ式が一目で理解しにくい場合、その目的を果たしていません。説明的な名前を持つ名前付き関数の方が優れています。
  • 再利用性: 同じロジックを複数の場所で必要とする場合は、DRY(Don't Repeat Yourself:繰り返しを避ける)の原則に従い、def を使用して一度定義します。

ベストプラクティスの使用例を強化する、明確で読みやすい例を見てみましょう。ファイル ~/project/lambda_best_practice.py を開き、以下のコードを追加してください。

## A list of dictionaries
students = [
    {'name': 'Alice', 'grade': 88},
    {'name': 'Bob', 'grade': 95},
    {'name': 'Charlie', 'grade': 72}
]

## A good use of lambda: sorting a list of dictionaries by a value
sorted_by_grade = sorted(students, key=lambda student: student['grade'])

print("Sorted by grade:", sorted_by_grade)

## For comparison, a more complex task is better with a named function.
## For example, if you needed to apply a curve and check for a minimum score,
## a 'def' function would be much clearer than a complex lambda.
def process_grade(student):
    curved_grade = student['grade'] * 1.05
    return max(curved_grade, 75) ## Ensure a minimum score

processed_grades = [process_grade(s) for s in students]
print("Processed grades:", processed_grades)

ファイルを保存して実行します。

python3 ~/project/lambda_best_practice.py

以下の出力が表示されます。

Sorted by grade: [{'name': 'Charlie', 'grade': 72}, {'name': 'Alice', 'grade': 88}, {'name': 'Bob', 'grade': 95}]
Processed grades: [92.4, 99.75, 75.60000000000001]

最初の部分は、ラムダの明確で適切な使用例を示しています。2 番目の部分は、名前付き関数の方が適しているシナリオを示しています。常に、自分自身や他の人が読みやすく理解しやすいコードを書くことを優先してください。

まとめ

この実験(Lab)では、Python のラムダ関数の基礎を学びました。まず、その構文と、def で定義される標準関数との違いを理解しました。次に、引数がゼロ、一つ、複数のラムダを作成する練習をし、それらを変数に代入して呼び出す方法を確認しました。

重要なポイントは、ラムダ関数を(特に sorted() のような)高階関数の引数として使用する実践的な応用であり、これによりカスタムのソートロジックを簡潔に定義できることでした。さらに、デフォルト引数や即時実行関数式(IIFE)のような高度なテクニックも探りました。最後に、ラムダを使用するためのベストプラクティスを確認し、ラムダは単純な一度限りのユースケースには強力ですが、可読性と保守性を常に優先し、より複雑なロジックには名前付き関数を選択すべきであることを強調しました。