こんにちは。PyQサポートです。
今回は「**kwargs
の前の/
」の記述に関する質問です。
質問
最初のコードを実行するとTypeErrorになりますが、模範解答のように**kwargs
の前に/
を書くとエラーになりません。**kwargs
の前に/
をつける意味を教えてください。
プログラムの該当箇所
TypeErrorになるコード
def update(dct, **kwargs): dct.update(kwargs) dct = {'year': 2019} update(dct, year=2020) print(dct) try: update(dct, dct=2020) print(dct) except TypeError as e: print('TypeError:', e)
模範解答のコード
def update(dct, /, **kwargs): dct.update(kwargs) dct = {'year': 2019} update(dct, year=2020) print(dct) try: update(dct, dct=2020) print(dct) except TypeError as e: print('TypeError:', e)
回答
**kwargsの前の/が表すもの
**kwargsの前に/
をつけることで、位置引数とキーワード引数を明確に分離することができます。これは、「Positional-only parameterss」と呼ばれています。実際のコードでその動きを見てみましょう。
2つのコードの違いは、最初の行だけです。 模範解答のコードに沿って解説します。
1回目のupdate
で行われる処理
関数update
では「kwargs
の内容で、辞書dict
を更新」しています。
kwargs
はキーワード引数で渡された値です。
以下の処理は {'year': 2019}
という辞書と、キーワード引数 year=2020
を update
関数に渡しています。
dct = {'year': 2019} update(dct, year=2020) print(dct)
このときupdate
関数に渡される値は以下のようになります。
dct
:{'year': 2019}
kwargs
:{'year': 2020}
def update(dct, /, **kwargs): dct.update(kwargs)
dct
も kwargs
も year
というキーを持っているので、結果は kwargs
の値である 2020
で上書きされます。
2回目のupdate
で行われる処理
続く処理も基本的には同じですが、引数が違います。
try: update(dct, dct=2020) print(dct) except TypeError as e: print('TypeError:', e)
ここでポイントは、 dct=2020
というキーワード引数を渡していることです。
もし def update(dict, /, **kwargs)
が、 def update(dict, **kwargs)
の場合これはエラーになります。
なぜなら dct
という同じ名前の引数が2つ指定されているからです。
しかし、 /
をつけることで、「位置引数は位置引数、キーワード引数はキーワード引数」と明確に分離されます。
なので上記の処理はエラーになりません。
まとめ
この問題は /
の挙動の違いを確認できます。
ぜひ /
を付けてエラーがでないこと、 /
を外してエラーがでることを確認してください。
併せて下記のブログの「Positional-only parameterss」の項を読むと、より理解できますよ。