【Python初心者】アンパック（*、**）の基本｜リスト・辞書をバラして渡すテクニック

Pythonでは、リストや辞書の中身を「バラして」渡すテクニックがよく使われます。  
これを<strong>「アンパック（unpack）」</strong>と呼びます。

一見難しそうに見えますが、慣れるとPythonらしいきれいなコードが書けるようになります。  
この記事では、アンパックの基本から、よく使われるパターンまでをわかりやすく整理します！

## アンパックとは？
アンパックとは、リストや辞書の中身をバラして、関数などに渡すテクニックです。

- `*` を使うとリストやタプルをバラして渡せます。
- `**` を使うと辞書をバラして渡せます。

これを使うことで、複数の値をスマートに処理できるようになります。

## * を使ったアンパックの基本

### リストやタプルのアンパック

リストの中身をバラして出力してみましょう。
```py
lst = [1, 2, 3]
print(*lst)
```

出力：
```
1 2 3
```

このように、リストの各要素がスペース区切りで出力されました。  
`*` を付けることで、リストそのものではなく「中身だけ」を取り出して渡すことができます。


### 関数へのリストアンパック

たとえば、関数に複数の引数を渡したい場合にも便利です。
```py
def add(a, b, c):
    return a + b + c

lst = [1, 2, 3]
print(add(*lst))
```

出力：
```
6
```

普通なら `add(1, 2, 3)` と個別に渡す必要がありますが、  
リストの中に値がまとまっているときでも `*lst` と書くだけでOKです！



## ** を使ったアンパックの基本

### 辞書のアンパック

今度は辞書をバラして関数に渡してみます。
```py
def greet(name, age):
    print(f"{name} is {age} years old.")

info = {'name': 'Alice', 'age': 25}
greet(**info)
```

出力：
```
Alice is 25 years old.
```
`**info` とすることで、  
- `name='Alice'`
- `age=25`  
という形で、それぞれの**キーと値を対応させて**関数に渡すことができました！

#### 【補足】辞書のアンパックは「キーワード引数」に変換する

辞書を `**辞書` の形でアンパックするときは、  
その中身（キーと値）を**キーワード引数にバラして**渡すためだけに使います。

そのため、
- キーワード引数を受け取れる関数（例：`def greet(name, age):`）には渡せる
- 受け取れないキーワードを持つ辞書を渡すとエラーになる

注意しましょう！

（参考例：失敗するケース）
```py
info = {'name': 'Alice', 'age': 25}
print(**info)  # → エラー：print() got an unexpected keyword argument 'name'
```
`print()` はキーワード引数を受け付けないためエラーになります。

:::note warn
<strong>【さらに補足】print()は一部キーワード引数を受け付けます</strong>
実は `print()` 関数には  
- sep：複数オブジェクトの間に挟む文字（デフォルトは半角スペース）
- end：出力の最後に付ける文字（デフォルトは改行 `\n`）
- file：出力先（デフォルトは標準出力。ファイルオブジェクトを指定可能）
- flush：出力を強制的にフラッシュするか（デフォルトはFalse）

など、もともと受け付けるキーワード引数が存在します。

そのため、例えば次のような辞書は渡してもエラーになりません。

（例：成功するケース）
```py
    info = {'sep': '！', 'end': '！！\n'}
    print('いくぞ', 1, 2, 3, 'ダー', **info)
```
出力：
```
いくぞ！1！2！3！ダー！！
```
このように、辞書のキーが関数で受け取れる名前なら、アンパックして渡すことができます。  
一方、受け取れない名前（`name`など）ならエラーになります。
:::

## 実践編：アンパックの応用

### リストの結合にも使える

リスト同士をスマートに合体させることもできます。
```py
a = [1, 2]
b = [3, 4]
c = [*a, *b]
print(c)
```

出力：
```
[1, 2, 3, 4]
```
普通はループで追加したりしますが、アンパックを使えば**簡単にリスト同士を結合**できます！



### 関数の可変長引数（*args, **kwargs）

ここまで学んだアンパックは、関数定義にも応用できます！
```py
def func(*args, **kwargs):
    print(args)
    print(kwargs)

func(1, 2, 3, name="Alice", age=25)
```
出力：
```
(1, 2, 3)
{'name': 'Alice', 'age': 25}
```
- `*args` で複数の引数をまとめて受け取る
- `**kwargs` でキーワード引数（名前付きの引数）をまとめて受け取る

こうした「自由な数の引数」を受けるテクニックにもアンパックは使われています！

ここで注意したいのは、

- 関数**定義側**（`*args`, `**kwargs`）では、**引数をまとめる（パックする）**
- 関数**呼び出し側**（`*リスト`, `**辞書`）では、**引数をバラす（アンパックする）**

という違いがあることです。

:::note info
なお、パックが行われる条件は、  
**関数定義時に仮引数リストの中で `*` や `**` を使った場合**です。  
`args` や `kwargs` という名前自体には特別な意味はなく、名前は自由につけることができます（慣例として `args`, `kwargs` がよく使われています）。
:::

## アンパックの注意点

- `*リスト` や `**辞書` を使うときは、**対応する数や名前が正しいか**に注意しましょう。
- 間違った数や違う名前の引数を渡すと、**エラー**になります。

（例）
```py
def add(a, b):
    return a + b

lst = [1, 2, 3]
print(add(*lst))  # → エラー！
```
リストの要素数（ここでは3個）が関数の引数（2個）と合っていないのでエラーになります。


## 発展編：拡張アンパック（Extended Iterable Unpacking）

Pythonでは、関数の引数だけでなく、  
変数への代入時にも `*` を使って複数の値をまとめることができます。  
これを「拡張アンパック」と呼びます。

（例）
```py
say = 1, 2, 3, 'ダー'
*count, last = say
print(count)  # [1, 2, 3]
print(last)   # 'ダー'
```
このように、リストやタプルの一部をまとめて受け取ることができます。

### 仮引数と拡張アンパックの違い

| パターン | データ型 |
|:---|:---|
| 関数の仮引数 `*args` | タプルになる |
| 拡張アンパック `*count` | リストになる |

使う場面によってデータ型も異なるので注意しましょう！

## まとめ

- `*` → リストやタプルをバラして渡す
- `**` → 辞書をバラして渡す
- 関数にまとめて引数を渡したり、リストを簡単に結合したりするときに大活躍！

アンパックを使いこなすと、Pythonらしいスッキリしたコードが書けるようになると思いました。 
使いこなせるようにしていきます！