【Python】よく見かける仮引数の形式を確認してみた( *args とか **kwargs など)

python でよく見かける仮引数の形式を、ドキュメントを見ながら確認していきたいと思います。

https://docs.python.org/ja/3/tutorial/controlflow.html#more-on-defining-functions

## デフォルトの引数値

> 一つ以上の引数に対してデフォルトの値を指定する形式

他の言語でも見かける、引数のデフォルト値を指定する方法。

```python
def ask_ok(prompt, retries=4, reminder='Please try again!'):
    print('prompt:', prompt)
    print('retries:', retries)
    print('reminder:', reminder)

# 定義している引数よりも少ない個数の引数で関数を呼び出せる
ask_ok('Do you really want to quit?', 1)
# prompt: Do you really want to quit?
# retries: 1
# reminder: Please try again!
```

## キーワード引数

>関数を kwarg=value という形式の キーワード引数 を使って呼び出すこともできます。

実引数で ``kwarg=value`` 形式で関数に渡す。引数の順番は関係ない。

```python
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print('voltage:', voltage)
    print('state:', state)
    print('action:', action)
    print('type:', type)

parrot(1000)
# voltage: 1000
# state: a stiff
# action: voom
# type: Norwegian Blue
```

必須引数とオプション引数を渡す

```python
parrot(5, state='pushing up the daisies')
# voltage: 5
# state: pushing up the daisies
# action: voom
# type: Norwegian Blue
```

キーワード引数を2つ渡す(必須引数をキーワード引数で指定)

```python
parrot(action='VOOOOOM', voltage=1000000)
# voltage: 1000000
# state: a stiff
# action: VOOOOOM
# type: Norwegian Blue
```

キーワード引数は位置引数の後ろでなければならない

```python
parrot(type='Bondi blue', 'dead')
#   File ".\app.py", line 53
#     parrot(type='Bondi blue', 'dead')
#                               ^
# SyntaxError: positional argument follows keyword argument
```

## **kwargs

可変長のキーワード引数を受け取る。関数で定義した以上のキーワード引数を受け取れる。

> 仮引数の最後に **name の形式のものがあると、それまでの仮引数に対応したものを除くすべてのキーワード引数が入った辞書 (マッピング型 --- dict を参照) を受け取ります。

```python
def cheeseshop(kind, **kwargs):
    print('kind:', kind)
    print(kwargs)
    print('kwargs [shopkeeper]:', kwargs['shopkeeper'])
    print('kwargs [client]:', kwargs['client'])

cheeseshop("Limburger",
            shopkeeper="Michael Palin",
            client="John Cleese",
            sketch="Cheese Shop Sketch")
# kind: Limburger
# {'shopkeeper': 'Michael Palin', 'client': 'John Cleese', 'sketch': 'Cheese Shop Sketch'}
# kwargs [shopkeeper]: Michael Palin
# kwargs [client]: John Cleese
```

引数に dict を渡す。dict をキーワード引数で渡すには、``**`` キーワードを使用する。

```python
arg_dict = {"a": 1, "b": 2}
check_kwargs(3, **arg_dict)
# 3
# {'a': 1, 'b': 2}
# 1
```

``**`` キーワードを使用しないとエラーになる。

```python
check_kwargs(3, arg_dict)
# Traceback (most recent call last):
#   File ".\app.py", line 84, in <module>
#     check_kwargs(3, arg_dict)
# TypeError: check_kwargs() takes 1 positional argument but 2 were given
```

引数にリストを渡してもエラーになる。

```python
l = [1, 2, 3]
check_kwargs(3, **l)
# Traceback (most recent call last):
#   File ".\app.py", line 98, in <module>
#     check_kwargs(3, **l)
# TypeError: check_kwargs() argument after ** must be a mapping, not list
```

## *args

可変長の位置引数をタプルで受け取ります。関数で定義した以上の位置引数を受け取れる。

```python
def pos_only_arg(arg, *args):
    print(arg)
    print(type(args))
    print('args index 0:', args[0])
    print('sum *args:', sum(args))

pos_only_arg(1, 2, 3)
# 1
# <class 'tuple'>
# args index 0: 2
# sum *args: 5
```

キーワード引数は受け取らない。

```python
pos_only_arg(1, 2, 3, name='jim')
# Traceback (most recent call last):
#   File ".\app.py", line 17, in <module>
#     pos_only_arg(1, 2, 3, name='jim')
# TypeError: pos_only_arg() got an unexpected keyword argument 'name'
```

リストやタプルをアンパックして関数に渡すには、``*`` 演算子を使用する

```python
args = [3, 6]
pos_only_arg(1, *args)
# 1
# <class 'tuple'>
# args index 0: 3
# sum *args: 9
```