Python学習チャンネル by PyQ

Pythonのオンライン学習プラットフォームPyQのオフィシャルブログです

「Pythonのargs、kwargsとは?」可変長引数に関する質問への回答

f:id:kenken0326:20200312122830p:plain

こんにちはid:hirokikyです。
今回はPyQの学習サポートプランでよくいただく*args**kwargsに関する質問です。
この機能は必ず知っていないといけないというものではありませんが、デコレーターを定義する際やクラスの継承をする際に必要となってきます。
ぜひ基本をここでシッカリと押さえておきましょう!

いただいた質問

可変長位置 *args と可変長キーワード **kwargs の役割がピンときません。

回答

まずPythonにおける *args**kwargs は、関数が引数をうけとる方法の1つだと覚えておきましょう。
たとえば def hello(name):name は、hello関数の引数です。これと同じように *args も引数に過ぎません。

まず *args から理解しよう

まず *args が何かについて理解しましょう。以下のhello関数は *args を使った関数です。
hello関数には "hiroki", "saito" という2つの位置引数を渡して呼び出しています。

def hello(*args):
    print(args)
    
hello("hiroki", "saito")  # ('hiroki', 'saito') と表示されます

実行すると ('hiroki', 'saito') と表示されます。
これはhello関数内のargs引数に、呼び出し時に渡された2つの引数がタプルに入ってくるからです。
このように *args は単純に引数を受け取る方法の1つに過ぎません。

このhello関数の代わりに、以下のような普通のhello関数を定義して、タプルを使って関数を呼び出しても結果は違いありません。

def hello(args):
    print(args)
    
t = ("hiroki", "saito")  # タプルを定義する
hello(t)  # ('hiroki', 'saito') と表示されます

つまり3行にまとめると以下のような仕組みです。

  1. def hello(*args):のように関数を定義する
  2. hello("hiroki", "tsutomu")のように引数を複数渡せる
  3. hello 関数内で args は、渡された引数のタプルになる

**kwargs を理解しよう

**kwargs も基本的には *args と考え方は同じです。
hello関数を **kwargs を使って書いてみましょう。
hello関数には name="hiroki", hometown="osaka" という値を渡して呼び出します。

def hello(**kwargs):
    print(kwargs)

hello(name="hiroki", hometown="osaka")  # {'name': 'hiroki', 'hometown': 'osaka'} と表示されます

実行すると {'name': 'hiroki', 'hometown': 'osaka'} と表示されます。
**kwargs とした場合は、 name="hiroki" のようにキーワード引数として渡した値が、 {"name": "hiroki"} のような辞書として関数内で使えます。

基本的な考え方は *args**kwargs は同じで、hello関数に任意の数の引数を渡せるようにするものです。
*args は位置引数がタプルに、 **kwargs はキーワード引数が辞書として渡されます。

名前は何でもOK

ここまで *args**kwargs と呼んできましたが、この引数名は自由です。
たとえば以下のhello関数では *names という引数の名前にしています。

def hello(*names):
    print(names)

この場合は names がタプルになります。
**kwargs も同じで、 **options**profile など任意の名前にできます。
ポイントは *** を引数の前に書くことです。

何と呼べば良いもの?

*args**kwargs というと何と呼べば良いのか少しややこしいですね。
それぞれ可変長位置引数、可変長キーワード引数と呼びます。「hello関数のargsは可変長位置引数です」のように使うと良いでしょう。
簡単に、「argsは可変長引数です」と言っても伝わることは多いです。

用語集 - Python3ドキュメント https://docs.python.org/ja/3/glossary.html#term-parameter

どこで使われるもの?

一番わかりやすい例としては、 print 関数そのものです。
print 関数には任意の数の引数を渡せます。
これは print 関数が可変長引数として引数を受け取るからです。

print("私は", "hiroki", "という名前です", "!")  # 「私は hiroki という名前です !」と表示されます

もし自分で関数を定義しようというときも、可変長引数は活用できます。
ですが多くの場合において、普通の関数を定義するのであれば普通の引数としてタプルや辞書を受け取るほうがわかりやすいと私は感じます (書き方の好みのレベルになります)。

デコレーターを定義する場合や、クラスの継承をするときに可変長引数を受け取ることが多くなるでしょう。
たとえば以下の show_args デコレーターは、どんな引数を受け取る関数に対しても使えるよう作られています。
これはデコレーターを理解していないと難しいかと思いますので、わからない場合は「なるほど、こう活用する場もあるのか」と知っていただければ十分です。

def show_args(f):
   """ 関数につけると、実行のたびに引数を表示するようにするデコレーター
   """
   def _wrapped(*args, **kwargs):
       print(args)
       print(kwargs)
       return f(*args, **kwargs)
   return _wrapped
   

@show_args
def foobar(name, required=False):
    ...

まとめ

Pythonの *args**kwargs という可変長引数について説明しました。
PyQでもこれらについて学べるコンテンツがありますので、ぜひ併せてご活用ください。

可変長引数については以下で学べます。

pyq.jp

デコレータについてはこちらで学べます

pyq.jp

また、ビープラウド著書の「自走プログラマー」にも可変長引数について記載しています。下記のURLから可変長引数に関する部分を抜粋したページに飛べますのでご覧ください。

9:関数の引数に可変長引数を乱用しない — 自走プログラマー【抜粋版】

Copyright ©2017-2020 BeProud Inc. All rights reserved.