続・関数の引数
【 目次 】
関数の引数について、述べ足りなかった事があったので。
引数について
いまさらながら、プログラミングにおける関数の引数,仮引数と実引数とは
- 引数 - Wikipedia
外部から値を渡される特別な変数として指定されるのが仮引数。関数(等)を呼出す式において、仮引数に対応する式(あるいはその値)が実引数である。実行時には、実引数の値を仮引数が受け取る。
キーワード引数とキーワード無しの引数のバリエーション
「キーワード引数についてのまとめ」でキーワード引数にも使い方がいろいろあると述べた。
キーワード引数とキーワード無しの引数の指定の仕方の組み合わせで、関数呼び出し時に指定した引数(実引数)が関数のどの引数(仮引数)に渡されるかに、いろいろなパターンがあって思わぬ結果になるので注意!
しつこいようだが、あらためてまとめてみた。
「そんな事、わかっているよ」と言われそうだが。
以下のような関数funcが定義されているとすると
def func(arg1, arg2, *args, **kwargs): print "arg1=", arg1 print "arg2=", arg2 print "args=", args print "kwargs=", kwargs
キーワード無しの引数を指定
以下のように引数をすべてキーワード無しの引数で指定すると
func("arg1", "arg2", "arg3", "arg4")
実行結果
arg1= arg1 arg2= arg2 args= ('arg3', 'arg4', 'arg5') kwargs= {}
必須の引数以外の残りの引数はすべてargsに格納される。
キーワード無しなのでkwargsには何も渡されない。
キーワード付き引数を指定
全ての引数をキーワード付き引数で指定すると
func(arg5="arg5", arg4="arg4", arg3="arg3", arg2="arg2", arg1="arg1")
実行結果
arg1= arg1 arg2= arg2 args= () kwargs= {'arg3': 'arg3', 'arg4': 'arg4', 'arg5': 'arg5'}
名前付きなので引数の順番は関係ない。
今度はargsには何も渡されない。
必須の引数以外の残りの引数はすべてkwargsに格納される。
キーワード付き引数の後ろにキーワード無しの引数は指定できない。
キーワード付き引数の後ろにキーワード無しの引数を指定すると
func(arg1="arg1", "arg2", arg3="arg3", "arg4", arg5="arg5")
実行結果
SyntaxError: non-keyword arg after keyword arg
キーワード無しの引数をキーワード付き引数の後に指定したとpythonに怒られた。
キーワード無しの引数とキーワード付き引数の混在指定
キーワード無しの引数とキーワード付き引数の混在指定すると
func("arg1", "arg2", "arg3", arg4="arg4", arg5="arg5")
実行結果
arg1= arg1 arg2= arg2 args= ('arg3',) kwargs= {'arg4': 'arg4', 'arg5': 'arg5'}
必須の引数以外のキーワード無しの引数arg3はargsに、キーワード付きのarg4,arg5はkwargsに格納される。
しかし、次の場合には、
func("arg1", "arg2", arg3="arg3", arg4="arg4", arg5="arg5")
実行結果
arg1= arg1 arg2= arg2 args= () kwargs= {'arg3': 'arg3', 'arg4': 'arg4', 'arg5': 'arg5'}
arg3をキーワード付きに変更すると、当然の事ではあるがarg3もkwargsに格納される事になる。
*引数や**引数の引数名をキーワード付き引数として指定する事はできない
*引数や**引数の引数名argsやkwargsをキーワード付き引数として指定して
func("arg1", "arg2", args=("arg3", "args4"), kwargs={"arg5_key": "arg5_value"})
以下のような結果を期待しても、
ダメヨ、ダメダメ。
このような結果にはならない
args= ("arg3", "args4") kwargs= {'arg5_key': 'arg5_value'}}
kwargs引数の辞書要素として、args要素とkwargs要素に格納されてしまう事になる。
実行結果
arg1= arg1 arg2= arg2 args= () kwargs= {'args': ('arg3', 'args4'), 'kwargs': {'arg5_key': 'arg5_value'}}
「引数リストのアンパック」と「キーワード付き引数」
引数リストのアンパックで述べたように*引数や**引数をまとめて渡す事ができる。
*引数にタプル値を渡すと
func("arg1", "arg2", *("arg3", "arg4"), arg5="arg5")
実行結果
arg1= arg1 arg2= arg2 args= ('arg3', 'arg4') kwargs= {'arg5': 'arg5'}
更に、**引数に対しても辞書を渡してやると
func("arg1", "arg2", *("arg3", "arg4"), **{"arg5_key":"arg5_value", "arg6_key":"arg6_value"})
実行結果
arg1= arg1 arg2= arg2 args= ('arg3', 'arg4') kwargs= {'arg5_key': 'arg5_value', 'arg6_key': 'arg6_value'}
しかし、キーワード引数に対してはこのような事(引数リストのアンパック)はできないようだ。
以下のコードはエラーになる。
func("arg1", "arg2", args=*("arg3", "arg4"), kwargs=**{"arg5_key":"arg5_value", "arg6_key":"arg6_value"})