[Python]可変長引数と引数展開でコードをスッキリさせる

Pythonには可変長引数という便利な機能があります。

可変長引数とは

関数の定義で引数の最初に*(アスタリスク)をつけることで、
関数の呼び出し側で、引数の数を任意に変更できます。

サンプル

コード

def variable_args(*args):
    print(len(args), ' items:')
    print('--------------------')
    for arg in args:
        print(arg)
    print('--------------------')

variable_args('First',  1, 2, 3)
variable_args('Second', 4, 5, 6, 7)

実行結果

4  items:
--------------------
First
1
2
3
--------------------
5  items:
--------------------
Second
4
5
6
7
--------------------

慣例的にargsを使うようですが、引数名は何でも良いです。
場合によって渡す引数の数を変えたい場合などに使えます。

キーワード可変長引数

関数の定義で引数の最初に**(アスタリスク2個)をつけることで、
関数の呼び出し側で、キーワード引数の名称、数を任意に変更できます。

サンプル

コード

def variable_kwargs(**kwargs):
    print(len(kwargs), ' items')
    print('--------------------')
    for k, v in kwargs.items():
        print(k,':',v)
    print('--------------------')

variable_kwargs(first=1, second=2)
variable_kwargs(third='three', fourth='four', fifth='five')

実行結果

2  items
--------------------
first : 1
second : 2
--------------------
3  items
--------------------
third : three
fourth : four
fifth : five
--------------------

こちらも慣例的にkwargsという名前を使ってますが、何でも良いです。

引数展開

リストや辞書に*をつけると、それらを展開して引数として渡すことができます。

具体的なコードを交えて説明します。

リストの展開

さきほど作ったvariable_argsメソッドに、リストを渡してみます。

l1 = ['First', 1, 2, 3]


print('-----そのまま渡す-----')
variable_args(l1)

print('-----展開して渡す-----')
variable_args(*l1)

実行結果

-----そのまま渡す-----
1  items:
--------------------
['First', 1, 2, 3]
--------------------
-----展開して渡す-----
4  items:
--------------------
First
1
2
3
--------------------

*なしでは、l1というリストを1つの引数として渡しているだけですが、
*をつけると、リストの中身を一つずつ引数として渡すことができます。
上記例では言い換えると、
variable_args('First', 1, 2, 3)
と同じ意味になります。

タプルでも同様です。

辞書の展開

さきほど作ったvariable_kwargsメソッドに辞書を展開して渡します。
引数の前に**をつけて渡します。

コード

d1 = {'first': 1, 'second':2}

variable_kwargs(**d1)

実行結果

2  items
--------------------
first : 1
second : 2
--------------------

なお、**なしでそのまま渡すとエラーになります。

コード

variable_kwargs(d1)

実行結果

Traceback (most recent call last):
(中略)
TypeError: variable_kwargs() takes 0 positional arguments but 1 was given

引数の展開では、リストや辞書の中身を展開して渡しているだけなので、関数の定義元が可変長引数である必要はありません。
以下のようなメソッドでも使えます。
ただし、リストの中身は引数の数と一致している必要があります。

コード

def fixed_args(arg1, arg2):
    print(arg1)
    print(arg2)

l2 = ['Fixed', 'args']

fixed_args(*l2)

実行結果

Fixed
args

まとめ

可変長引数、キーワード可変長引数によって、関数に汎用性・拡張性を持たせることができます。
また、引数の展開によって、関数呼び出し時のコードをやすくまとめることができます。

*のせいでなんだか小難しい印象を与えがちですが、慣れると非常に便利です。

参考