このページでは、Python の関数の引数に利用される *
と **
について説明していきます。
自分自身では利用する機会は少ないかもしれませんが、Python の標準モジュールや外部モジュールのソースコードを見てみると下記のような引数を持つ関数が定義されていることが多いです。
def func(arg1, *args, **kwargs):
pass
*
と **
の意味合いを知らない場合、上記のような関数定義を見ると混乱してしまうと思います。ですが、このページを読んで *
と **
の意味合いを理解していただければ、上記のような関数定義を見た際に内容がすんなり理解できるようになります。また、*
と **
の意味合いを理解していただくことで、自分自身で *
と **
を使いこなすこともできるようになります!
Contents
仮引数における *
と **
まず前提として、引数には2つの種類があります。仮引数と実引数です。仮引数は関数定義に使用される引数のことです。関数定義時には「この関数ではこれらの引数を受け取りますよー」ということを定義しておく必要があります。これらが仮引数となります。
それに対し、関数呼び出し時に指定する引数は実引数と呼ばれます。簡単に言えば、関数の引数に実際に渡す値のことになります。
Python においては仮引数の引数名に *
と **
を指定することが可能ですし、実引数として指定する変数名に *
と **
を指定することも可能です。ですが、*
と **
の意味合いは仮引数と実引数で全く異なります。逆の意味合いになると考えても良いです。
では、どういった意味合いになるのか?
この点について、まずは仮引数の方から説明していきたいと思います。
このページでは *引数名
や **引数名
などの 引数名
の左側に *
や **
が付加された場合の仮引数について説明していきます
下記のように、単に *
のみを仮引数として指定した場合、「*
よりも右側の引数はキーワード引数として指定しなければならない」ことを示す記述となります
def func(a, b, *, c, d, e):
上記の場合は、a
, b
は位置引数で指定可能ですが、c
と d
と e
はキーワード引数で指定しなければ関数呼び出し時に例外が発生します
*
のみを指定する場合と *引数名
を指定する場合とで意味合いが異なるため、その点にご注意ください
可変長の引数であることを示す記号
仮引数における *
と **
は可変長引数であることを示す記号になります。*引数名
や **引数名
が指定されている場合、それぞれ下記のような可変長引数を受け取ることを示す仮引数となります。
*引数名
:可変長の位置引数**引数名
:可変長のキーワード引数
この “可変長” とは、関数呼び出し時に指定可能な引数の数が可変であることを示す言葉になります。例えば下記のように定義されている関数であれば、1つの位置引数と、可変長の位置引数および可変長のキーワード引数を受け取ることができます。
def func(arg1, *args, **kwargs):
print('args:', args)
print('kwargs:', kwargs)
print('type of args:', type(args))
print('type of kwargs:', type(kwargs))
そのため、下記のようにargs
に位置引数4つ、kwargs
にキーワード引数3つを指定して関数を呼び出すこともできますし、
func(1, 2, 3, 4, 5, a=6, b=7, c=8)
下記のようにargs
に位置引数1つ、kwargs
にキーワード引数5つを指定して関数を呼び出すこともできます。
func(1, 2, a=6, b=7, c=8, d=9, e=10)
さらに、下記のようにargs
と kwargs
を指定せずに関数を呼び出すこともできます。受け取れる引数の数が可変長なので、いくらでもこのような例は示すことができます。
func(1)
このように、*
と **
は仮引数において可変長の引数を扱うための記号となります。そして、*
に関しては可変長の位置引数を、**
に関しては可変長のキーワード引数を扱うための記号となります。
なので、*args
のような *
が指定された仮引数が定義された関数を呼び出す際には、任意の個数の位置引数が指定可能となりますし、**kwargs
のような **
が指定された引数を受け取る関数を呼び出す際には任意の個数のキーワード引数が指定可能となります。
まずは、この点を覚えておきましょう!
指定された引数がどのように扱われるかは関数によって異なりますが、親切なモジュール等であればドキュメントに扱われ方が記載されていることも多いです。
スポンサーリンク
関数が受け取るのはパックされたデータ
次はもう少し踏み込んで仮引数における *
と **
について説明していきます。関数呼び出し側からすれば可変長の引数を指定してやれば良いことになることは先ほど説明しました。では、関数側では、*
と **
が指定された引数はどのように扱われるのでしょうか?
これは、先ほども示した下記のような func
関数を実際に実行してみると分かりやすいです。
def func(arg1, *args, **kwargs):
print('args:', args)
print('kwargs:', kwargs)
print('type of args:', type(args))
print('type of kwargs:', type(kwargs))
func(1, 2, 3, 4, 5, a=6, b=7, c=8)
上記のスクリプトを実行すれば、func
関数の可変長引数である *args
に4つの引数が、**kwargs
に3つの引数が指定されることになります。func
関数では、これらの args
と kwargs
そのもの、および、これらの型を出力するようにしています。実際に実行すれば、下記のような出力結果が得られると思います。
args: (2, 3, 4, 5) kwargs: {'a': 6, 'b': 7, 'c': 8} type of args: <class 'tuple'> type of kwargs: <class 'dict'>
すごく分かりやすい結果が出力されましたね!
この結果からも分かるように、args
はタプル型であり、kwargs
は辞書型のデータとなります。つまり、関数呼び出し時に指定したバラバラの位置引数が1つのタプルにパックされ、さらにバラバラのキーワード引数が1つの辞書にパックされた状態で関数に渡されることになります。
そして、これらは普通のタプル型・辞書型のデータとなるので、通常のタプルや辞書の使い方で利用することが可能です。
タプルや辞書を受け取るためのものではない
ここまでの話は分かりやすいのではないかと思います。でも、ここで次のような疑問が湧いてくるのではないでしょうか?
要は、例えば上記のような func
関数を呼び出す際に次のような引数の指定の仕方でも問題ないのではないか?と言う疑問になります。
touple_data = (2, 3, 4, 5)
dict_data = {
'a': 6, 'b': 7, 'c': 8
}
func(1, touple_data, dict_data)
これは実際に実行してみれば分かります。実行した時の出力結果は下記のようになります。
args: ((2, 3, 4, 5), {'a': 6, 'b': 7, 'c': 8}) kwargs: {} type of args: <class 'tuple'> type of kwargs: <class 'dict'>
あらら…。args
がtouple_data
と dict_data
を受け取ってしまいましたね…。そしてこれらが1つのタプルの中に格納される形になってしまっています。
まぁ、これは冷静に考えれば当然の結果になります。touple_data
も dict_data
も両方とも位置引数で指定しているので、func
関数はこれらがパックされたデータを args
として受け取ることになります。
じゃあ、ちょっと作戦を変えて下記のように kwargs
になんとかして辞書データを渡すようにしてみましょう!
touple_data = (2, 3, 4, 5)
dict_data = {
'a': 6, 'b': 7, 'c': 8
}
func(1, touple_data, kwargs=dict_data)
この場合の結果は下記のようになります。
args: ((2, 3, 4, 5),) kwargs: {'kwargs': {'a': 6, 'b': 7, 'c': 8}} type of args: <class 'tuple'> type of kwargs: <class 'dict'>
この場合も結果は意図したものではないですね…。この場合、func
関数は kwargs
というフィールドの値に dict_data
がセットされた辞書を kwargs
として受け取ることになってしまっています。また、args
側も “1つのタプル” が要素であるタプルを受け取ってしまっています。
こういった動作からも分かるように、仮引数で指定される *
と **
は、あくまでも関数呼び出し側が可変長引数を指定可能にするためのものとなります。関数側で受け取るデータの型がタプルや辞書であるからといって、関数呼び出し時にタプルや辞書を引数に指定すると意図した通りの動作にならないので注意してください。
では、この前提に基づき、次の2つの関数 main_func
と sub_func
について考えてみましょう。この main_func
から sub_func
を呼び出す際に、引数として main_func
が受け取った args
と kwargs
の各引数をそのまま sub_func
の引数に指定したいとします。
def sub_func(arg1, *args, **kwargs):
print('args:', args)
print('kwargs:', kwargs)
print('type of args:', type(args))
print('type of kwargs:', type(kwargs))
def main_func(arg1, *args, **kwargs):
sub_func(引数)
main_func(1, 2, 3, 4, 5, a=6, b=7, c=8)
この時、main_func
が受け取った args
をそのまま sub_func
が args
引数で受け取り、main_func
が受け取った kwargs
をそのまま sub_func
が kwargs
引数で受け取れるようにするには、どのようにして main_func
は sub_func
を呼び出せば良いのでしょうか?
この例のように、可変長引数を受け取った関数が他の関数にそのままその可変長引数を渡したいようなケースは実際の開発でも多々あります。
ちなみに、先ほどの例でも説明したように、下記のように引数を指定して sub_func
を実行するのではダメです。この場合、sub_func
は main_func
が受け取った args
と kwargs
をパックしたものを args
引数で受け取ることになります。逆に kwargs
は1つも引数を受け取れません。
def main_func(arg1, *args, **kwargs):
sub_func(arg1, args, kwargs)
もしかしたらいろんな方法があるかもしれませんが、最も簡単な方法は sub_func
を呼び出す際に *
と **
を利用することになると思います。つまり、下記のように sub_func
の実引数に *args
と **kwargs
を指定します。
def main_func(arg1, *args, **kwargs):
sub_func(arg1, *args, **kwargs)
では、このように実引数に指定した場合、*
と **
はどのように作用するのでしょうか?
それについて、次の章で解説していきます。
実引数における *
と **
では、続いて実引数における *
と **
について説明します。
仮引数における * と ** の最初にも説明しましたが、”実引数における *
と **
” は “仮引数における *
と **
” とは逆のような意味を持つ記号となります。
前述した通り、*
と **
が指定された仮引数は、それぞれ可変長の位置引数と可変長のキーワード引数を受け取る引数となります。そして、関数呼び出し時に実引数として指定された可変長の引数は、1つのタプルおよび1つの辞書にパックされて関数に渡されることになります。
スポンサーリンク
アンパックを命令する記号
それに対し、関数呼び出し時に指定する実引数に指定するリストやタプル等のデータに *
を指定した場合、 それらのデータの各要素がアンパックされて、それぞれ個別の位置引数として関数に指定されることになります。
同様に、関数呼び出し時に指定する実引数に指定する辞書のデータに **
を指定した場合、 その辞書のデータの各要素がアンパックされて、それぞれ個別のキーワード引数として関数に指定されることになります。
つまり、実引数における *
と **
はアンパックを命令する記号となります。
前述の通り、仮引数における *
と **
の場合、可変長引数を受け取る際にそれぞれの引数がパックされて渡されることになります。実引数においてはアンパックされ、仮引数においてはパックされることになるため、この点に注目すれば *
と **
は実引数に指定される場合と仮引数に指定される場合とで逆の意味合いになります。
タプルや辞書を可変長引数として指定することが可能
さて、ここで 仮引数における * と ** でも示した下記の例について考えてみましょう。
def sub_func(arg1, *args, **kwargs):
print('args:', args)
print('kwargs:', kwargs)
print('type of args:', type(args))
print('type of kwargs:', type(kwargs))
def main_func(arg1, *args, **kwargs):
sub_func(arg1, *args, **kwargs)
main_func(1, 2, 3, 4, 5, a=6, b=7, c=8)
ここで、main_func
と sub_func
を呼び出す際に、引数がどのようにして扱われるのかについて説明したいと思います。
まず、main_func
関数の引数の定義により、この関数は1つの位置引数(arg1
)、可変長の位置引数(args
)、可変長のキーワード引数(kwargs
)を受け取ることになります。
上記のように main_func
関数を実行すれば、1
が arg1
として、2
・3
・4
・5
がタプルにパックされた (2, 3, 4, 5)
を args
として、a=6
・b=7
・c=8
が辞書にパックされた {'a': 6, 'b': 7, 'c': 8}
を kwargs
として main_func
が受け取ることになります。
さらに、 main_func
が sub_func
を呼び出す際には下記のように実引数が指定されています。
def main_func(arg1, *args, **kwargs):
sub_func(arg1, *args, **kwargs)
この場合、関数が呼び出される前に、*
と **
の命令が実行されることになります。*args
では args
をリストやタプル等からアンパックして各要素に分解する処理が実施されます。引数 args
は (2, 3, 4, 5)
を受け取っているため、このアンパックにより、sub_func
呼び出し部分は下記のように変化することになります。
def main_func(arg1, *args, **kwargs):
sub_func(arg1, 2, 3, 4, 5, **kwargs)
さらに **kwargs
では kwargs
を辞書からアンパックして各要素に分解する処理が実施されます。引数 kwargs
は {'a': 6, 'b': 7, 'c': 8}
を受け取っているため、このアンパックにより、sub_func
呼び出し部分は下記のように変化することになります。
def main_func(arg1, *args, **kwargs):
sub_func(arg1, 2, 3, 4, 5, a=6, b=7, c=8)
つまり、*
と **
の命令により、sub_func
関数呼び出し時の引数は main_func
関数呼び出し時に指定した引数と同じものになります。さらに、sub_func
関数の引数定義は main_func
関数と全く同じですので、main_func
関数呼び出し時と同じ動作によって、1
が arg1
として、2
・3
・4
・5
がタプルにパックされた (2, 3, 4, 5)
を args
として、a=6
・b=7
・c=8
が辞書にパックされた {'a': 6, 'b': 7, 'c': 8}
を kwargs
として sub_func
が受け取ることなります。
このように、可変長引数としてタプルや辞書を受け取った関数から他の関数に全く同じ可変長引数を指定することは、関数呼び出し時に指定する実引数に対して *
と **
を指定することで簡単に実現することが可能です。
もし、Python が実引数に対する *
と **
の指定によってアンパックする機能を持っていないのであれば、上記と同様の動作を実現するためにプログラマーは引数で受け取ったタプルや辞書を自力でアンパックする必要があります。これは面倒です…。
ですが、Python が実引数に対する *
と **
の指定によってアンパックする機能を備えているため、タプルや辞書から可変長引数への変換が簡単に行うことができるようになっています。
この仮引数における *
と **
と実引数における *
と **
の意味合いを理解しておけば、可変長引数を扱うサンプルコードも混乱することなく読めるようになりますし、自身で可変長引数を扱う関数やメソッドも開発しやすくなります。
単なるパック・アンパック機能として利用も可能
ここからは参考情報になります。
ここまで、関数の仮引数や実引数に指定する場合の *
と **
について説明していきましたが、実は関数の仮引数と実引数に指定する時以外でも *
や **
を利用することが可能で、単なるパック・アンパック機能としてこれらを利用することもできます。
例えば下記が実行されれば、x
と y
は 1
と 2
を参照するようになりますが、z
に関しては残りの 3
・4
・5
をパックして生成されたリスト [3, 4, 5]
を参照するようになります。
x, y, *z = 1, 2, 3, 4, 5
*
を利用せずに下記のように記載した場合、左辺の変数の数と右辺の値の数が合わないので例外が発生することになります。
x, y, z = 1, 2, 3, 4, 5
このように、*
と **
を単なるパック・アンパックする機能として利用することも可能です。
ですが、一番利用する機会が多いのは、ここまでも説明してきたような「関数の仮引数や実引数に指定する場合」になると思います。そして、これらを利用する目的は可変長引数の受け取りや受け渡しを実現することになります。
ということで、*
と **
に関しては、まずはこれらが可変長引数を実現するためのものであり、これが実現可能なのは *
と **
にパック・アンパック機能があるためであることを覚えておくくらいで良いと思います!
スポンサーリンク
まとめ
このページでは、Python における *
と **
について説明しました!
特に関数の仮引数に *引数名
と **引数名
が存在する場合、その関数は可変長引数を受け取ることが可能となります。そして、タプルやリスト・辞書など、複数のデータがパックされた変数を関数呼び出し時に可変長引数として指定するために、実引数として *変数名
や **変数名
が指定されることになります。これにより、関数呼び出し前に変数がアンパックされて別々の引数として指定されるようになります。
冒頭でも触れたように、Python のコードを読んでいると関数の仮引数や実引数に *
と **
が指定されていることも多いです。これらの意味を知らないとコードを読む際に混乱することになりますが、今回説明した内容を理解していただければコードの意味合いもスッキリ理解できるようになると思いますので、是非 *
と **
の意味合いについては理解しておきましょう!