ラムダと内包表記

これら3つの機能には共通点があります。通常は数行かかるアイデアを、単一の読みやすい式で表現できます。うまく使えば、コードはより短く明確になります。下手に使えば、読めなくなります。この章では、それぞれをいつ使うか、いつ止めるかをカバーしています。
ラムダ関数
ラムダは名前のない1式関数です。lambdaキーワードで作成します。その真の有用性は、最初に名前付き関数を定義することなく、必要な場所にインラインで書けることです。これがsorted()で有用にしています。
double = lambda x: x * 2
double(5) # 10これは以下と同等です。
def double(x):
return x * 2ほとんどの場合、defを使ってください。ラムダの本当の利点は1つです。必要な場所にインラインで書くことができ、名前を付ける必要がありません。これがsorted()、map()、filter()で有用にしています。
players = [("太郎", 87), ("花子", 74), ("次郎", 92)]
sorted(players, key=lambda p: p[1]) # スコアでソート(昇順)
sorted(players, key=lambda p: p[1], reverse=True) # スコアでソート(降順)ラムダなしで、key=引数のためだけに名前付き関数を定義する必要があります。ラムダは意図をローカルで見えるようにします。
ラムダは複数の引数を取ることができます。
add = lambda a, b: a + b
add(3, 4) # 7ラムダをいつ使うか: 1か所で使われる小さい式の場合のみです。成長している場合、または再利用する必要がある場合は、適切なdefを書いてください。複数の演算子にまたがるラムダまたは条件が必要なラムダは、通常defに切り替えることを示唆しています。
lambdaキーワードで書かれた、名前のない小さい1行関数です。存在する全理由は、sorted()のインラインkey=になることで、1つの仕事のためだけに別の関数を定義しないようにすることです。1つのきれいな式を超えて長くなった瞬間、私は実際のdefを書いて、それについてより良い気分になります。 リスト内包表記
Pythonで最も一般的な変換:シーケンスを取り、各項目に何かをし、新しいリストを返します。リスト内包表記はこれを1つの読みやすい行で行います。[expression for item in iterable]。ifでフィルタを追加することもできます。
長いやり方:
numbers = [1, 2, 3, 4, 5]
squares = []
for n in numbers:
squares.append(n ** 2)リスト内包表記:
squares = [n ** 2 for n in numbers]構造は常に同じです。[expression for item in iterable]。
scores = [87, 42, 96, 55, 71]
scaled = [s * 1.1 for s in scores] # 10%のボーナスを適用
as_grades = [f"{s}/100" for s in scores] # 各1つをフォーマット[expression for item in iterable]はシーケンスを取り、各項目に1つのことを行い、新しいリストを返します。左から右に読むと、それは正確に何をするかを言います。これが、別の言語から翻訳するのではなく、Pythonを書いているように感じさせてくれた最初のPython機能でした。 条件でフィルタリング
テストに合格した項目のみを含めるためのif句を追加してください。結果は、条件がTrueである項目のみを含む新しいリストです。
numbers = [1, 2, 3, 4, 5, 6, 7, 8]
evens = [n for n in numbers if n % 2 == 0] # [2, 4, 6, 8]
odds = [n for n in numbers if n % 2 != 0] # [1, 3, 5, 7]scores = [87, 42, 96, 55, 71, 38]
passing = [s for s in scores if s >= 60] # [87, 96, 71]
failing = [s for s in scores if s < 60] # [42, 55, 38]if conditionを追加して、テストに合格した項目のみを保つ:[x for x in data if x > 0]。偽りに来るものはすべて新しいリストの外に残されます。それはドアマンがいる同じ内包表記です。 ネストされた内包表記
内包表記をネストして、リストのリストを単一のリストにフラット化できます。左から右に読んでください。各行について、その行の各項目について、項目を含めます。
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [item for row in matrix for item in row]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]左から右に読んでください。matrixの各行について、その行の各項目について、itemを含めます。
ネストされた内包表記は急速に混乱する可能性があります。解析に1瞬以上かかる場合は、ループを明示的に書いてください。
辞書内包表記
辞書内包表記は辞書を1つの式で構築し、リスト内包表記と同じ考えを使用します。{key: value for item in iterable}。リスト内包表記と同様にifでフィルタを追加してください。
names = ["太郎", "花子", "次郎"]
scores = [87, 74, 92]
score_map = {name: score for name, score in zip(names, scores)}
# {"太郎": 87, "花子": 74, "次郎": 92}フィルタ付き:
passing = {name: score for name, score in score_map.items() if score >= 80}
# {"太郎": 87, "次郎": 92}words = ["apple", "banana", "cherry"]
word_lens = {word: len(word) for word in words}
# {"apple": 5, "banana": 6, "cherry": 6}{key: value for item in iterable}は1行で辞書を構築し、キーと値の間にコロンがあるリスト内包表記と同じ形です。`.items()`と組み合わせて、既に持っている辞書を再形成したり、`zip()`と組み合わせて2つのリストを1つのマッピングに縫い合わせたりします。最後に`if`を追加して、欲しいペアのみを保ちます。 セット内包表記
セット内包表記は、1つの式でセットを構築し、波括弧とコロンなし。結果はセットであるため、重複は自動的に削除されます。
words = ["apple", "banana", "cherry", "apple"]
unique = {w.lower() for w in words} # {"apple", "banana", "cherry"}セット内包表記は、ユニークな値が必要で、順序を気にしない場合に使用します。
ジェネレータ式
ジェネレータは、角括弧の代わりに括弧を持つリスト内包表記のようです。重要な違い:リスト内包表記はメモリ全体をすべて一度に構築します。ジェネレータは必要に応じて1回に1つの値を生成します。大きなシーケンスの場合、これははるかに少ないメモリを使用します。
squares_gen = (n ** 2 for n in range(1000000))total = sum(n ** 2 for n in range(1000000)) # sum()はジェネレータを消費するsum()、max()、min()、any()のような関数にジェネレータを直接渡す場合、追加の括弧を削除できます。
total = sum(n ** 2 for n in range(1000)) # 2つでなく1セットの括弧ほとんどの毎日のコードでは、リスト内包表記は問題ありません。大規模なデータセットまたはストリーミングデータを処理する場合、メモリ内のすべての保持は浪費になる場合、ジェネレータを使用します。
zip()
zip()は2つ以上のシーケンスからの項目をペアにして、それらを並行してループできます。最も短いシーケンスで停止します。2つのリストが互いに対応する場合、インデックスの管理を避けるクリーンな方法です。
names = ["太郎", "花子", "次郎"]
scores = [87, 74, 92]
for name, score in zip(names, scores):
print(f"{name}: {score}")
# 太郎: 87
# 花子: 74
# 次郎: 92zip()は最短のシーケンスで停止します。シーケンスが異なる長さの場合、埋め値でitertools.zip_longest()を使用します。
ジッピングされたペアのリストから2つの別のリストに変換するには、zip(*pairs)を使用します。
pairs = [("太郎", 87), ("花子", 74), ("次郎", 92)]
names, scores = zip(*pairs)
# names = ("太郎", "花子", "次郎")
# scores = (87, 74, 92)*pairsはリストを別の引数にアンパックするため、zip(*pairs)はzip(("太郎", 87), ("花子", 74), ("次郎", 92))になります。*演算子は関数章で説明されています。
zip()は、インデックスを手動で管理せずに複数のシーケンスを並行して繰り返すクリーンな方法でもあります。
before = [10, 20, 30]
after = [15, 18, 35]
for b, a in zip(before, after):
change = a - b
print(f"{b} -> {a} ({'+' if change >= 0 else ''}{change})")map()とfilter()
map()とfilter()は、内包表記がする何をしている古い関数スタイルのツールです。古いコードでそれらを見かけるため、それが意味することを知る価値があります。新しいコードでは内包表記を好みます。ほとんどのPython開発者にはより読みやすいです。
numbers = [1, 2, 3, 4, 5]
list(map(lambda x: x ** 2, numbers)) # [1, 4, 9, 16, 25]
list(filter(lambda x: x % 2 == 0, numbers)) # [2, 4]内包表記を好みます。ほとんどのPython開発者にはより読みやすいです。既に存在する名前付き関数がある場合、map()を使用します。
strings = ["1", "2", "3"]
numbers = list(map(int, strings)) # [1, 2, 3] (内包表記より清潔)実践で
プレイヤーリストをフィルタリング、スコアでランク付けしsortedとラムダで、列挙位置で印刷します。
players = [
{"name": "太郎", "score": 87},
{"name": "花子", "score": 42},
{"name": "次郎", "score": 96},
{"name": "三郎", "score": 55},
]
passing = [p for p in players if p["score"] >= 60]
ranked = sorted(passing, key=lambda p: p["score"], reverse=True)
score_map = {p["name"]: p["score"] for p in ranked}
for i, (name, score) in enumerate(score_map.items(), start=1):
print(f"{i}. {name}: {score}")
