今さらPython3 (28) - * と **

第4章絶賛進行中です。なんとなく知っていたけど、実はよく分かっていなかったなんて話もチラチラ出てきて、遠回りしてよかったなと思う今日この頃です。

入門 Python 3

入門 Python 3

*argsって何?

20年くらい前に初めてCを触ったときとか、2年くらい前にObjective-Cを触ったときに*が出てきてポインタですというのは習ったんだよね。Pythonにはポインタはないと聞いていたのに、*argsって出てきて何これ?と少し嫌な気分になったんだけど、今日は積年の疑問を晴らすことができると密かに期待w

>>> def print_args(*args):
...     print('Positional argument tuple:', args)
...
>>> print_args()
Positional argument tuple: ()
>>> print_args(3, 2, 1, 'Wait!', 'uh...')
Positional argument tuple: (3, 2, 1, 'Wait!', 'uh...')

この例を見ると、*argsはTupleだというのは分かる。なら引数がtupleならいいんじゃない?と試す。

>>> def print_tuple(i_tuple):
...     print('Positinal argument i_tuple:', i_tuple)
...
>>> print_tuple()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: print_tuple() missing 1 required positional argument: 'i_tuple'
>>> def print_tupple(i_tuple=()):
...    print('Here you can see the tuple:', i_tuple)
...
>>> print_tupple()
Here you can see the tuple: ()
>>> print_tupple(('Hello', 'World'))
Here you can see the tuple: ('Hello', 'World')
>>>

同じ動きはできちゃったけど、初期値の割当の要否が違うのかなと理解。i_tupleというので試したときは=()を付けないとダメだった。

>>> def print_note(required1, required2, *args):
...     print('Need this one:', required1)
...     print('Need this one, too:', required2)
...     print('All the rest:', args)
...
>>> print_note('cap', 'gloves', 'scarf', 'monocle', 'mustache wax')
Need this one: cap
Need this one, too: gloves
All the rest: ('scarf', 'monocle', 'mustache wax')
>>>

ここまでやって、この*argsの必要性が見えてきた感じ。print_note(関数名間違えた)に引数渡すときに、必須である前の2つのパラメータと境目なく引数を渡している。境目なくと言っているのは、*argsの部分だけタプルで括っている訳ではないという意味。結果として、単純にこの関数には2つかそれ以上の引数を受け入れるというのが表現できているんだね。あと、例を見るときはいつも*argsなのは、慣例に基づくもので、必ずしもその名前でなくても構わないと。多分、argumentsの略かな?

・・・プログラミングの世界で慣例を破ると可読性が下がるだけなので従いましょう。

**kwargsとは?

もう1つの**kwargsもよく見る。これも実例から見ていこう。

>>> def print_kwargs(**kwargs):
...     print('Keyword arguments:', kwargs)
...
>>> print_kwargs()
Keyword arguments: {}

これは辞書だね。

>>> print_kwargs(wine='merlot', entree='mutton', dessert='macaroon')
Keyword arguments: {'dessert': 'macaroon', 'entree': 'mutton', 'wine': 'merlot'}

引数名とその値が辞書形式で関数の中に取り込まれるんだね。**kwargsという名称を使うのも慣例とのこと。あと、*argsと**kwargsを両方指定する場合は、*argsを先にというお約束は、引数の話のところで出た話と同じようなイメージなので理解しやすいかな。

大げさじゃなく、Python触りはじめて以来の積年の疑問が解けた!

(つづく)