とても初歩的な内容だが、仕事でプログラミングをしているときにどツボにハマったのでメモしておく。
##可変長引数とは
可変長引数とは、自由に引数の大きさを変更できる引数のことである。Pythonだと、引数の中身をtupple型に格納してくれる*args
(arguments)と、dict型として受け取ってくれる**kargs
(keyword arguments)が用意されている。
詳しい使い方等については、以下のページに詳しい。
##可変長引数を使うときの問題点
###argsの場合
では、本題に移ろう。まず、次のような関数を考える。
def hoge(a,b,*c):
print(a)
print(b)
print(c)
if __name__ == "__main__":
a="Hello!"
b="World!"
c=["I am a","nooby","programmer!!"]
hoge(a,b,c)
Hello!
World!
(['I am a', 'nooby', 'programmer!!'],)
この関数は、引数が3つあるが、もしそのうちの1つを忘れてしまったらどうなるだろうか?
def hoge(a,b,*c):
print(a)
print(b)
print(c)
if __name__ == "__main__":
a="Hello!"
b="World!"
c=["I am a","nooby","programmer!!"]
hoge(a,c)
Hello!
['I am a', 'nooby', 'programmer!!']
()
問題なく動いてしまった。
そう、可変長引数は「変数の大きさを自由に変えられる引数」だった。言い換えれば、長さは0であっても良いことを意味する。
###**kargsの場合
以上の特徴は、**kargs
でも同様だが、こちらはキーワードが必要になるので比較的間違いに気づきやすいかもしれない。
def foo(hoge,fuga,**hage):
print(hoge)
print(fuga)
print(hage)
if __name__ == "__main__":
hoge="Hello!"
piyo="World!"
hage=["I am a","nooby","programmer!!"]
foo(hoge,fuga=hage[0],c=hage[1],d=hage[2])
Hello!
I am a
{'c': 'nooby', 'd': 'programmer!!'}
これは、**kargs
の一部としたかったkeywordを、関数fooの2番目の引数であるfuga
としてしまったことに起因している。引数と一致させなければきちんとエラーが返る。
def foo(hoge,fuga,**hage):
print(hoge)
print(fuga)
print(hage)
if __name__ == "__main__":
hoge="Hello!"
piyo="World!"
hage=["I am a","nooby","programmer!!"]
foo(hoge,b=hage[0],c=hage[1],d=hage[2])
Traceback (most recent call last):
File "hoge.py", line 12, in <module>
foo(hoge,b=hage[0],c=hage[1],d=hage[2])
TypeError: foo() missing 1 required positional argument: 'fuga'
##対策
以上のように、特に*args
を用いた際にケアレスミスの要因となる場合があることがわかった。以上のような問題を起こさないためには、*args
がtupple型、**kargs
がdict型として格納されていることを活用して、次のようにすると良いだろう。
def hoge(a,b,*c):
if len(c)==0: raise TypeError("*c is not given")
print(a)
print(b)
print(c)
if __name__ == "__main__":
a="Hello!"
b="World!"
c=["I am a","nooby","programmer!!"]
hoge(a,c)
Traceback (most recent call last):
File "hoge.py", line 11, in <module>
hoge(a,c)
File "hoge.py", line 2, in hoge
if len(c)==0: raise TypeError("*c is not given")
TypeError: *c is not given