*
と **
🌟💫🌟💫🌟💫🌟💫🌟💫🌟💫
Python Tips LT会 - vol.3
2022/05/25 nikkie
>>> *(1, 2)
Python 3.10 で動作確認
現在サポートされている Python 3.7 以降で再現します(はず)
NHKのドラマ『17才の帝国』に㊗️ 出演
#17才の帝国 第2話を視聴。
— nikkie にっきー シオンv0.0.1開発中⚒ (@ftnext) May 21, 2022
え、待って!
プログラミング言語のPythonが出演してる!!
PythonがNHKに!!!
あと真木くんのエディタがAtom!
VSCodeじゃなくてAtom!!
AtomもNHKに!!!(再現画像)
コードはめっちゃ突っ込みどころが😂
真木くんのコードはこちらからhttps://t.co/z7xE4nKEYg pic.twitter.com/sOPTpfR9pf
#ミノ駆動本 『良いコード/悪いコードで学ぶ設計入門』
Javaのコード例で示された設計を Pythonにどう適用するか 考えたい!
>>> *(1, 2)
考えながらお聞きください
*
と **
二項演算子( *
は乗算、 **
はべき乗)
可変長引数( *args, **kwargs
)
アンパック演算子
他にも浮かんだらぜひ教えてください🙏
*
catch-all アンパック代入
キーワード専用引数
他にも浮かんだらぜひ教えてください🙏🙏
アンパック
関数の引数
紹介できないものはAppendixへ
*
と **
🌟💫🌟💫アンパック演算子
関数と *
や **
キーワード専用引数
可変長引数
アンパックする演算子としての *
と **
を紹介します
タプルのパック: 詰める (パッキング)
シーケンスのアンパック:中の物を 取り出す
パック・アンパックは Pythonチュートリアル 5.3. で紹介されます
イテラブルアンパック演算子
辞書アンパック演算子
用語は「What's New In Python 3.5」より
要素を一度に 1 つずつ返せるオブジェクト
シーケンス
辞書
ファイルオブジェクト
など(※イテラブルを自作もできます)
リスト
文字列
タプル
など(※自作もできます)
整数インデクスでアクセスでき、長さを返す
>>> # タプル (1, 2) は(シーケンスであり)イテラブル
>>> [*(1, 2)]
[1, 2]
>>> [*(1, 2), 3]
[1, 2, 3]
>>> [0, *[1, 2]]
[0, 1, 2]
>>> [*range(2), 2]
[0, 1, 2]
>>> [*"12", 3]
['1', '2', 3]
>>> (*(1, 2), 3)
(1, 2, 3)
タプルを書くときは必ずしも丸括弧で囲まなくてもいい (Pythonチュートリアル 5.3.)
>>> 1, 2
(1, 2)
>>> 1,
(1,)
>>> *(1, 2), 3
(1, 2, 3)
>>> *(1, 2)
SyntaxError
>>> *(1, 2)
File "<stdin>", line 1
SyntaxError: can't use starred expression here
>>> *(1, 2),
(1, 2)
カッコつけないタプルの書き方になっている!
>>> # 辞書はイテラブル
>>> fruits_prices = {"apple": 100, "banana": 50}
>>> *fruits_prices,
('apple', 'banana')
>>> def f():
... return 42, "spam"
...
>>> type(f())
<class 'tuple'>
カッコつけずに書いたタプル!
*iterable, v1, v2
で新しい タプル が返る
[*iterable, v1, v2]
とすれば新しいリスト
[*iterable]
だけでもリストにできる
イテラブルアンパック演算子
辞書アンパック演算子
>>> fruits_prices = {"apple": 100, "banana": 50}
>>> {**fruits_prices}
{'apple': 100, 'banana': 50}
>>> {**fruits_prices, "melon": 777}
{'apple': 100, 'banana': 50, 'melon': 777}
キーと値の組を 追加 した辞書
Python 3.5から可能になりました
>>> [*(1, 2), 3, *range(2)]
[1, 2, 3, 0, 1]
>>> d1, d2 = {"x": 11, "y": 22}, {"v": 101, "w": 201}
>>> {**d1, "z": -33, **d2}
{'x': 11, 'y': 22, 'z': -33, 'v': 101, 'w': 201}
知っていたので、一方の辞書をforで回さず、簡潔に書けました
>>> fruits_prices = {"apple": 100, "banana": 50}
>>> {**fruits_prices, **{"melon": 777}}
{'apple': 100, 'banana': 50, 'melon': 777}
なお、Python 3.9 以降は |
演算子で もっと簡単 に書けます
>>> fruits_prices | {"melon": 777}
{'apple': 100, 'banana': 50, 'melon': 777}
Guidoさん曰く「私も {**d1, **d2}
って書けるの忘れてた(意訳)」(PEP 584)
*
はイテラブルを、 **
は辞書をアンパックする演算子
*
や **
を使って、新しいタプル・リスト・辞書を作るやり方を紹介
PEP 448により *
や **
は 複数回 使えます!
Python Conference Japan 2022 は10/14(金)-16(日) 有明で開催
JST 6/13(月) 20:59まで
*
や **
🌟💫🌟💫関数の 引数 と絡めて *
や **
を紹介します
位置またはキーワード引数 (Pythonチュートリアル 4.8.3.1.)
位置引数としても渡せるし、キーワード引数(=名前付き引数)としても渡せる
>>> def calculate_bmi(height_m, weight_kg):
... return weight_kg / height_m / height_m
>>> calculate_bmi(1.58, 46)
18.426534209261334
>>> # すべてキーワード引数で渡せば、順番を変えられます
>>> calculate_bmi(weight_kg=46, height_m=1.58)
18.426534209261334
>>> # 位置引数はキーワード引数より先に来ます
>>> calculate_bmi(1.58, weight_kg=46)
18.426534209261334
*
引数の並びの中で、 *,
のあとの引数は、キーワード専用引数となる
必ず名前付き で渡さなければならず、位置引数としては渡せなくなる
>>> # 2つの引数をどちらもキーワード専用とした
>>> def calculate_bmi(*, height_m, weight_kg):
... return weight_kg / height_m / height_m
>>> calculate_bmi(weight_kg=46, height_m=1.58)
18.426534209261334
>>> calculate_bmi(1.58, 46)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: calculate_bmi() takes 0 positional arguments but 2 were given
関数呼び出しの意図を明確に するために使う(『Effective Python 第2版』項目25)
例えば複数の論理型フラグを使うような、紛らわしい関数呼び出し
脱線 IMO:フラグ引数は悪魔が潜みがちですよね(ref: #ミノ駆動本)
Python 3.8 から
拙記事 1月の #stapy で挙がった2つの質問に回答します:キーワード専用引数はいつから? 位置専用引数の使い所は?
*
や **
>>> def f(*args, **kwargs):
... print(f"{args=}")
... print(f"{kwargs=}")
*
が付いた args
や **
が付いた kwargs
について見ていきましょう
f"{args=}"
というf-stringf-stringはPython 3.6から(フォーマット済み文字列リテラル)
Python 3.8で =
指定子が有効に!(What's New In Python 3.8)
f"{variable=}"
は "variable=値"
という形式の文字列になる
*args
>>> f(1, 2, 3)
args=(1, 2, 3)
kwargs={}
位置引数たちは args
(タプル)に詰められる
>>> numbers = [1, 2, 3]
>>> f(numbers)
args=([1, 2, 3],)
kwargs={}
args
は要素1のタプル
args[0]
が [1, 2, 3]
>>> f(*numbers)
args=(1, 2, 3)
kwargs={}
イテラブルの要素が位置引数として渡された
**kwargs
>>> f(a=1, b=2, c=3)
args=()
kwargs={'a': 1, 'b': 2, 'c': 3}
キーワード引数たちは kwargs
(辞書)に詰められる
>>> values = {"a": 1, "b": 2, "c": 3}
>>> f(**values)
args=()
kwargs={'a': 1, 'b': 2, 'c': 3}
辞書のキーと値の組をキーワード引数として渡せました🙌
>>> f(*numbers, **values) # ただし、この順に限る
args=(1, 2, 3)
kwargs={'a': 1, 'b': 2, 'c': 3}
PEP 448「複数回使える」は関数の引数にも該当します
>>> f(*range(2), 2, *[3, 4])
args=(0, 1, 2, 3, 4)
kwargs={}
>>> f(**{"z": 1}, y=2, **{"x": 3})
args=()
kwargs={'z': 1, 'y': 2, 'x': 3}
*
や **
🌟💫🌟💫引数リスト中に *
を置くことで、それ以降を キーワード専用引数 にできる
*
を先頭に付けた引数は 可変長位置引数 、 **
を先頭に付けると 可変長キーワード引数
可変長{位置,キーワード}引数に、アンパック演算子を使って渡すこともできる
*
と **
🌟💫🌟💫{イテラブル,辞書}アンパック演算子
可変長{位置,キーワード}引数 + アンパック演算子との組合せ
これらは頻出ではないですが、 知っていたからこそ簡単に書けた瞬間 が訪れると思います
Enjoy development with stars! 🌟💫
追加をお楽しみに!
*