Python超入門(番外1):*arg と **kwarg

Pythonを習い始めていろいろできるようになってくると,新しい機能は必要になったときに応じてネットで調べるようになってくるかと思います.その際に,必要としている機能以外の知識が前提としている場合があり,実はたいした知識ではないのに難しく感じてしまう,もしくは余計に調べることが多くなってドツボにはまってしまうことがあります.そのような知識の一つに「*arg」とか「**kwarg」というものがあります.

ということで,今回はこの「*arg」と「**kwarg」について初心者向けの説明を試みます.内容としては,これらについて全く知らない人向けですね.簡単に言うと(自分を含む)初心者の方がビビらないようなお助け(という名目のメモ)です.堅苦しい説明は苦手なので,日本語での説明が多くなります.







*arg, **kwargs って何の略語?

“arg”は”argument”の略で,日本語では「(プログラミングでいう)引数」を意味しています.
“kwarg”は”keyword argument” の略で「キーワードとなる引数」という意味になりますね.「キーワードとなる」っていう言葉がピンと来ないかと思いますが,pythonで辞書型を扱うときに見出し語のことを”key”と読んだことをイメージしていただきたいです.実際この”kwargs”は辞書型と深く関係しています.

ズバリ,どういう事してくれるの?

Pythonにおいて *arg や **kwarg は「可変長引数(かへんちょうひきすう)」と呼ばれています.

Pythonで関数を定義したり用いたりする際に注意する点として,関数の定義のときと実際使うときで引数の数と順番が一致している必要がありましたね.しかし,プログラムをいろいろ作成しているうちに関数に追加したい引数があれこれ増えていく場合,増えるたびにすべての該当する関数の引数の部分を書き換えなくてはなりません.これはとても不便ですね.

そこで,「必要な引数の数が変わっても,プログラムに大きく変更を加えなくていい方法はないか...」と考え始めたときに,この可変長変数は役に立ちます.この可変長変数を用いると,名前の通り,変数の数が変わっても対応できる関数を作成することができます.

また,これは後述しますが,この可変長変数を実際プログラムで用いる際には,変数の前についているアスタリスク(*)が可変長変数の正体になります.なので,*や**のあとについている arg や kwarg という文字は実際コードを書く際にはほかの文字に変えていただいても構いません.

*arg の使い方

ではその可変長変数とやらがどのように使われるのか見ていきましょう.

引数が *arg だけの場合

先に *arg の機能を簡単に説明しますと「関数を使う際に引数としてあるものは全部受け取って,番号を付ける」ということをしています.受け取り方はタプルとして受けとります

これを念頭に,次のプログラムを書いて実行してみましょう.実行結果はプログラムの下に書いてあります.プログラムがやっていることは,「arg_check とうい関数で *arg を用いて arg が何をしているのかを見るためにいくつか出力してみる」ということをしています.

#######関数定義##########
def arg_check(*arg):
    print(arg)
    print(arg[0])
    print(arg[3])

#####関数に入れてみる変数定義#####
list = [5,6,7]
string = 'HOEE'
integer = 5
pi = 3.14

######関数の実行######
arg_check( list, string, integer, pi)
([5, 6, 7], 'HOEE', 5, 3.14)
[5, 6, 7]
3.14

変数定義の部分から読み始めると読みやすいかと思います.変数の型として様々なものを定義しましたが,関数を実行する最後の行でそれらのいろんな型の変数をすべて渡しています.「arg_check( list, string, integer, pi)」が実行された際に,arg_check という関数にかっこの中のすべての引数を関数に渡して,関数を実行させます.関数の定義の部分では引数を *arg としか書いていませんが,これ一文字で何個でも変数を受けとることができます.このとき引数たちはかっこの中に書いた順番にタプル型で渡され,最初の引数がarg[0]で順番にarg[1]…となります.print(arg)とすれば arg というタプルが表示され,argがタプルなので arg[0] のようにすればargというタプルに入っている最初の引数が表示されます.

引数が他にあって,最後に *arg が書いてある

関数の引数を *arg だけでなく他に書いている場合,*arg は「余った引数」として機能します.次の例を」見てみましょう.

#####関数定義############
def arg_check( x, *arg):
    print(x)
    print(arg)
    print(arg[0])

#######関数に入れる引数定義#####
list = [5,6,7]
string = 'HOEE'
integer = 5
pi = 3.14

#######関数実行#############
arg_check( list, string, integer, pi)
[5, 6, 7]
('HOEE', 5, 3.14)
HOEE

実行結果を見ると,argの要素の中にlistがありません.つまり,xという変数にはlistが入っていて,残りの変数がタプル型のargに順番に入れられているのがわかるかと思います.

この「余った引数」というのがポイントで,関数定義の引数の最後に *arg を付け加えると,関数の引数の数が合わないエラーが起きなくなることもわかります.そういう使い方もできるんですね.

「*」がこの可変長引数の本体

プログラム中のすべてのargという文字をほかの文字に変えても同じ機能をしてくれます.引数の「*」が可変長引数を意味しているということに注意しましょう.arg としても args としても機能に違いはありません.

ネットで調べていると可変長引数を表す文字としてよく arg と args が用いられていますがどちらでも同じことで,あくまでも慣例的なものになります.

**kwargs の使い方

**kwarg の基本的な使い方

*argと同じく可変長引数のことなのですが,関数の受け取り方が異なります.「*」が1個付いた*argがタプルとして余りの引数を受け取っていたのに対し,「*」が2個付いた **kwarg は辞書型の可変長引数を表しています

使い方としては,引数にイコール(=)があるときに機能してくれます.次の使用例を見てみましょう.

######関数定義###############
def kwarg_check(**kwarg):
    print(kwarg)
    print(kwarg['a'])

######関数の利用############
kwarg_check(a=1, b=2, c=3)

{‘a’: 1, ‘b’: 2, ‘c’: 3}
1

kawrg として受け取ったものを出力したものを見ると,関数を利用してる部分に注目して,引数の左側が辞書型のキー,右側がそのキーの値として扱われているのがわかります.

argのときはタプルだったのでarg[番号]とすることで要素を取り出せましたが,今回は辞書型だからkwarg[番号]という書き方は意味を成しません.**kwarg で受け取った可変長引数は辞書型の扱いをするべきです.

「**」がこの可変長引数の本体

argのときと同じく,プログラム中のすべてのkwargという文字をほかのに変えてもよいです.大事なのは,引数の「**」が辞書型の可変長引数を意味しているということです.

ネットで調べていると kwarg や kwargs がよく見受けられますが,機能としては全く同じことです.

関数(*arg, **kwarg) のメリット

先ほどチラッと書きましたが,引数が後で追加されることになっても,プログラム中で関数を定義している部分の変更しなくてもいいのは便利です.変数が増えたとしても arg の番号が増えるだけ,もしくは kwarg のキーが増えるだけなので...

また,kwarg を用いることで引数に変数名とその値を明示的に書けるのでコードを書く際の混乱も回避できますね.関数に機能を追加する際もkarg[‘変数名’]とすることで簡単に追加できちゃいます.

このブログについて

IAtLeX です.ブログをはじめてさほど時間がたっていないので,未熟な内容が多々あるかと思いますが,それも時間が解決してくれるはず...Python系の記事を着々と充実させていきたいです.投稿主についてはこちらを参照してください.

このブログについて - http://iatlex.com/about_blog/

コメント

  1. マツコ より:

    Python初心者のものです。大変わかりやすい説明ありがとうございました。一点、気づいた点がありました。「引数が *arg だけの場合」の項目で最後の実行結果は「5」ではなく「3.14」になるかと思うのですが・・・。

    1. IAtLeX より:

      ご指摘ありがとうございます!2017/06/24 12:03 に訂正いたしました。

      実行結果をちゃんとコピペしないと、こういうメチャクチャ致命的なミスが起きちゃうんですね…
      「マツコ」っていう名前だったのでぼろくそ言われるかと思ったのですが、メチャクチャ物腰柔らかいご指摘でしたね(笑)

  2. ケティ より:

    python初心者です。
    とても分かりやすかったです、ありがとうございます!!

マツコ へ返信する コメントをキャンセル

*