[Python]関数の引数単体アスタリスク(*)は何?【func(arg, *, kw):】

- Python -
2020.01.23
Python[パイソン]

PyQ(パイキュー)でPythonを勉強していて、こんな関数が出てきました。

def func(arg, *, kw1, kw2):
    print('arg =', arg)
    print('kw1 =', kw1)
    print('kw2 =', kw2)
    print()

初見で「(゚Д゚)ハァ?」となったのが、1行目のこの赤いやつです↓。

def func(arg, ✳︎, kw1, kw2):

なんだよここにあるアスタリスクは...!?

*args とか **kwargs とかともまた違う感じがする。

というわけで調べてみたら、「これって直感的にピンとこないやつだなぁ」という感想。

アスタリスク以降の引数を、キーワード引数で受け取ることを強制する

def func(arg, ✳︎, kw1, kw2): ...

この↑funcを呼び出すとき、

  1. func(1, 2, 3) とするとエラーになる。
  2. func(1, kw1=1, kw2=2) とすると正常に動く。

正常に動作する例:

def func(arg, *, kw1, kw2):
    print('arg =', arg)
    print('kw1 =', kw1)
    print('kw2 =', kw2)
    print()

func(1, kw1=1, kw2=1)

# 出力
# arg = 1
# kw1 = 2
# kw2 = 3

上記7行目赤線で、2番目と3番目の実引数の書式が「引数名(キーワード)=値」になっています。

引数1番目の arg は、アスタリスクの前にあり位置引数のため「値」のみ渡しています。

エラーになる例

def func(arg, *, kw1, kw2):
    print('arg =', arg)
    print('kw1 =', kw1)
    print('kw2 =', kw2)
    print()

func(1, 1, kw2=1)

# 出力
# TypeError: func() takes 1 positional argument but 2 positional arguments
# (and 1 keyword-only argument) were given

今度は、7行目でfuncに渡す2番目の引数が「引数名(キーワード)=値」の型になっていないためエラーになってしまいます。

エラーメッセージを見ると「1つの位置引数(arg)のみをとるはずが、2つの位置引数が渡されました」と出ているのもこの「*」の特徴を表しています。

くどいですが、funcに渡すべき2番目の引数は、 def func(arg, ✳︎, kw1, kw2)  と「アスタリスクの後ろ」に定義しているため、

func(1, 1, kw2=1) → NG

func(1, kw1=1, kw2=1) → OK

となります。

もちろん、

func(1, 1, 1) → これもNG

です。

アスタリスクを仮引数っぽく書いているのに、関数を呼ぶ時に実引数として何かをそのアスタリスクに向けて渡すわけではない点に注意!

公式ドキュメント(python.org)を探したんですが、見つからなかったのでクラスメソッドさんのブログでふむふむしました。

参考にした記事[python初心者向け]関数の引数のアスタリスク(*)の意味

アスタリスクによるキーワード引数強制に何のメリットがあるの?

引数の渡し間違えを絶対に防ぎたい時=品質が重要なとき、らしいです。

まだ実際に使うような場面に遭遇したことがないから実感が湧きませんが、関数を呼び出すときに定義元をよく確認しないと呼び出せないので「位置引数の渡す順番を間違えた」というミスを減らす効果はありそう。

おわりですm(_ _)m