検索ガイド -Search Guide-

単語と単語を空白で区切ることで AND 検索になります。
例: python デコレータ ('python' と 'デコレータ' 両方を含む記事を検索します)
単語の前に '-' を付けることで NOT 検索になります。
例: python -デコレータ ('python' は含むが 'デコレータ' は含まない記事を検索します)
" (ダブルクオート) で語句を囲むことで 完全一致検索になります。
例: "python data" 実装 ('python data' と '実装' 両方を含む記事を検索します。'python data 実装' の検索とは異なります。)
img_for_tre_tron

Tré Thộn を食べたことがありますか?
ベトナム・ビンズオン滞在中の方は是非注文して食べてみて!
絶対に美味しいです!
ホーチミン市内へも配達可能です。お問い合わせください。

Have you ever had "Tré Thộn" before?
If you're living at Bình Dương in Vietnam, you "must" try to order and eat it.
I'm sure you're very surprised how delicious it is!!
If you're in Hồ Chí Minh, you have a chance to get it too. Please call!!
>>
effective_python

【 Effective Python, 2nd Edition 】Python 3.8 で導入された assignment expression (walrus operator, :=) について 投稿一覧へ戻る

Published 2020年6月12日22:18 by mootaro23

SUPPORT UKRAINE

- Your indifference to the act of cruelty can thrive rogue nations like Russia -

assignment expression (代入書式?代入演算子?) では walrus operator (:=) が使用されます。
直訳すると「セイウチ演算子」。:= がおメメとキバに見えるからとか。


端的に言うと、変数へ値を割り当て、その変数を評価する、という2ステップを1度に済ませる、ということです。


以下、活用場面を見ていきましょう。


今日はレモネードの気分、冷蔵庫の中にレモンがあればレモネードを作りましょう、レモンは1個必要です。。


ref = {
"apple": 10,
"banana": 8,
"lemon": 3,
}



従来の記述:
count = ref.get("lemon", 0)
if count:
print("レモネードを作るよ!")
else:
print("あきらめた(泣)")



count 変数へまず値を割り当て、続けてその値を評価して処理が分岐します。
assignment expression を利用するとこれを端的に表現できます。


if count := ref.get("lemon", 0):
print("レモネードを作るよ!")
else:
print("あきらめた(泣)")



アップルジュースにはリンゴが3つ必要です。


従来の記述:
count = ref.get("apple", 0)
if count >= 3:
print("アップルジュースを作るよ!")
else:
print("あきらめた(泣)")



これも assignment expression を利用して表現できます。
ただしこの場合は、代入した結果を比較 (>=3) しその結果で分岐する (if) 、ために、assignment expression を () で囲む必要があります。


if (count := ref.get("apple", 0)) >= 3:
print("アップルジュースを4人分作るよ!")
else:
print("あきらめた(泣)")



ここで、冷蔵庫の中の果物の個数によって、バナナスムージー、アップルジュース、レモネードの順に判断して出してくれる自動ジューサーがあるとします。


バナナスムージーにはバナナが2本必要です。


このようなコードを記述する場合、Python には switch/case ステートメントがありませんから、if/elif/else のディープなネストで表現することが多々生じます。


従来の記述:
count = ref.get("banana", 0)
if count >= 2:
print("バナナスムージーでエナジー満タン!")
else:
count = ref.get("apple", 0)
if count >= 3:
print("アップルジュースで医者要らず!")
else:
count = ref.get("lemon", 0)
if count:
print("レモネードでスッキリさわやか!")
else:
print("お買い物に行ってきて...")



こんなときに assignment expression を利用すると、switch/case 文のような見た目の記述にすることができます。


if (count := ref.get("banana", 0)) >= 2:
print("バナナスムージーでエナジー満タン!")
elif (count := ref.get("apple", 0)) >= 3:
print("アップルジュースで医者要らず!")
elif count := ref.get("lemon", 0):
print("レモネードでスッキリさわやか!")
else:
print("お買い物に行ってきて...")



ただコンパクトに収まっただけではなく、ネストが浅い分読みやすさも増しているのではないでしょうか。


もう1つだけ assignment expression が有効な場面を見てみましょう。


冷蔵庫の中の果物を自動的に認識し、瓶詰めジュースを作っておいてくれるマシンがあるとします。


def pick_fruit() -> dict:
pass

def make_bottled_juice(fruit, count):
pass



従来の記述 その1:
bottles = []
fresh_fruit = pick_fruit()
while fresh_fruit:
for fruit, count in fresh_fruit.items():
bottled_juice = make_bottled_juice(fruit, count)
bottles.extend(bottled_juice)
fresh_fruit = pick_fruit()



この実装では、pick_fruit() を2箇所に記述しています。。


1回目は while ループに入るための初期条件をセットするため、2回目は新たなフルーツをセットするため。


この冗長性を排除するために、loop-and-a-half と呼ばれる構文を利用することができます。


従来の記述 その2:
bottles = []
while True: # Loop
fresh_fruit = pick_fruit()
if not fresh_fruit: # And a half
break

for fruit, count in fresh_fruit.items():
bottled_juice = make_bottled_juice(fruit, count)
bottles.extend(bottled_juice)



このイディオムで、条件をセットするための pick_fruit() の記述を1回にすることができますが、


while ステートメントがただの無限ループのために利用されているだけで何の条件判断も任されていない、


すべての条件制御が break ステートメントのみによって実現されている、


という点で、あまりエレガントとは言い切れなくなってしまっています。


そこで...


bottles = []
while fresh_fruit := pick_fruit():
for fruit, count in fresh_fruit.items():
bottled_juice = make_bottled_juice(fruit, count)
bottles.extend(bottled_juice)



いかがですか?


pick_fruit() からの値の取得、変数へのセット、その値に基づく while ステートメントでの評価が1行で収まっており、
コードの読解性、簡潔性が両立されているのではないでしょうか。


まとめ

* Assignment expression は walrus operator (:=) を利用し、変数への値の代入/評価を1行で行えるため、冗長性を削除できる。

* Assignment expression が長い書式中のサブ書式として含まれている場合は ( ) で囲む必要がある。

* Python では switch/case、do/while 構文は利用できないが、assignment expression を利用することで同様の機能を今までより簡潔、明白に実現することができる。

この記事に興味のある方は次の記事にも関心を持っているようです...
- People who read this article may also be interested in following articles ... -
【 Effective Python, 2nd Edition 】assignment expression (walrus operator, :=) を利用して内包表記におけるサブ書式の重複を回避しよう!
【 Using Asyncio in Python 】Python における asyncio を利用した非同期プログラム ( asynchronous programming ) の勉強を継続する前に、今一度スレッド ( thread ) についてのちょっとした復習ノート、まとめてみた
【 Effective Python, 2nd Edition 】プログラムを並列処理 ( concurrency ) パターンへ移行するタイミングとツールを考えるシリーズ 第 5 回 - 並列処理 ( concurrency ) のためにスレッド ( thread ) を利用する場合は concurrent.futures モジュールの ThreadPoolExecutor の導入を検討しましょう、の巻
【 Effective Python, 2nd Edition 】クロージャー関数 ( closure function ) の変数スコープについて - 参照と代入における違いを理解してますか?
【 Effective Python, 2nd Edition 】Python においてクラス属性に厳密な private が無いのは何故? できる限り利用すべきではない理由とは? それでも private の使用が有効な状況とは?
【 Effective Python, 2nd Edition 】入力元のデータサイズが大きい場合は、リスト内包表記 ( list comprehension ) ではなくジェネレータ式 ( generator expression ) の利用を検討しよう!
【 Effective Python, 2nd Edition 】* 書式 (starred expression) をアンパックで活用しよう!