Python3.xのアスタリスク逆引き

## 前書き

意外と簡潔にまとめた記事が無かったので書いた。
Python初心者がさっくり理解できることを目的としている。

## 関数を呼び出すとき
### アスタリスク `*`

```Python:ex_a1.py
my_list = [1, 2, 3]
print(*my_list)
```

```text:実行結果
1 2 3
```

**アンパック**と呼ばれるもので、引数としてリストやタプルなどを分解して渡すことを意味する。
つまり、上記の例の場合`print(my_list[0], my_list[1], my_list[2])`と同じ。

性質上、**可変長位置引数**の関数と非常に相性がいい。

### アスタリスク `**`

```Python:ex_a2.py
my_dict = {'sep': ' / ', 'end': ' おわり\n'}
print(1, 2, 3, **my_dict)
```

```text:実行結果
1 / 2 / 3 おわり
```

同じくアンパックだが、こちらは辞書などをキーワード引数として渡すことが出来る。
つまり上記の例の場合、`print(1, 2, 3, sep=' / ', end='おわり\n')`と同じ。

単体で使うことはあまりなく、だいたい**可変長キーワード引数**の関数と併せて使う。

## 関数を定義するとき
### アスタリスク `*` (仮引数名アリ)
```Python:ex_b1.py
def compute_product(*nums):
    ret = 1
    for num in nums:
        ret *= num
    return ret

print(compute_product(1, 2, 3))
```

```text:実行結果
6
```

**可変長位置引数** (あるいは単に可変長引数) を取る関数を定義するときに使う。
与えられた実引数はタプルにまとめられる。

通常の仮引数と組み合わせて使うことも可能である。
しかし、`*args`以降はキーワード引数として呼び出さなければならない。

```Python:ex_b2.py
def useless_func(a, b, *args, c, d):
    pass

useless_func(1, 2, 3, 4, 5, 6)     # NG
useless_func(1, 2, 3, 4, c=5, d=6) # OK
```

NGな方のコードを実行してしまうと、次のような例外が発生する。

```text:
TypeError: useless_func() missing 2 required keyword-only arguments: 'c' and 'd'
```

### アスタリスク `*` (仮引数名ナシ)
```Python:ex_b3.py
def useless_func(a, b, *, c, d):
    pass

useless_func(1, 2, 3, 4, c=5, d=6)  # NG
useless_func(1, 2, c=5, d=6)        # OK
```

アスタリスク以降の引数を、キーワード引数として受け取ることを強制できる。
可変長位置引数と異なり、余分な実引数を受け取ってしまうこともない。

NGな方のコードを実行してしまうと、次のような例外が発生する。

```text
TypeError: useless_func() takes 2 positional arguments but 4 positional arguments (and 2 keyword-only arguments) were given
```


### アスタリスク `**`
```Python:ex_b4.py
def useless_func(**kwargs):
    print(kwargs)

useless_func(a=1, b=2, c=3)
```

```text:実行結果
{'a': 1, 'b': 2, 'c': 3}
```

**可変長キーワード引数**を取る関数を定義するときに使う。
与えられた実引数は辞書としてまとめられ、キーワード・実引数値がそれぞれkey・valueとされる。

ありとあらゆる引数を受け取る関数を定義するときの定型はこんな感じ。

```Python:ex_b5.py
def useless_func(*args, **kwargs):
    print(args, kwargs)

useless_func(1, 2, 3, a=1, b=2, c=3)
```

```text:実行結果
(1, 2, 3) {'a': 1, 'b': 2, 'c': 3}
```

## 代入文で用いられるアスタリスク `*`
```Python:ex_c1.py
a, b, *other = [1, 2, 3, 4, 5]
print(a, b, other)
```

```text:実行結果
1 2 [3, 4, 5]
```

左辺に複数の要素を置くとき[^1]、要素のひとつにアスタリスクを付けることが出来る。
上記の例では、左から順に代入を終えたあと、余った要素がotherに放り込まれる。

[^1]: 実は `*lst, = range(10)` といった書き方もできるが、あまり見ないので紹介は控えた。普通は `lst = list(range(10))` とか `lst = [*range(10)]` と書くと思う。

次のように書いているのと同じ。

```Python:ex_c2.py
my_list = [1, 2, 3, 4, 5]
a = my_list[0]
b = my_list[1]
other = my_list[2:]

print(a, b, other)
```

## リストを定義するときのアスタリスク `*`
```Python:ex_d1.py
list1 = [1, 2, 3]
list2 = [9, 8, 7]

my_list = [*list1, *list2]
print(my_list)
```

```text:実行結果
[1, 2, 3, 9, 8, 7]
```

この例に限っては`list1 + list2`でも同じことができるが、覚えておくと便利。
見た目も先のアンパックに似ているので、特に違和感なく受け入れられるだろう(多分)。

## 辞書を定義するときのアスタリスク `**`
```Python:ex_e1.py
fruit_dict = {'リンゴ': 'apple', 'オレンジ': 'orange'}
vegetable_dict = {'キュウリ': 'cucumber', 'にんじん': 'carrot'}

food_dict = {**fruit_dict, **vegetable_dict}
print(food_dict)
```

```text:実行結果
{'リンゴ': 'apple', 'オレンジ': 'orange', 'キュウリ': 'cucumber', 'にんじん': 'carrot'}
```

辞書を合成して新たな辞書を作るときによく用いられる。

**追記**
Python3.9で辞書のマージ演算子`|`が提供され、より簡潔に記述できるようになった。

## 式と式の間
###アスタリスク `*`
```Python:ex_f1.py
def triple(a):
    return 3 * a
```

ただの掛け算。
気を付ける点があるとすれば、NumPyでは[アダマール積](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%80%E3%83%9E%E3%83%BC%E3%83%AB%E7%A9%8D)に用いられていることくらい。

また、イテラブルの反復にも用いられる。特に文字列。

```Python:ex_f2.py
print('spam' * 3)   # spamspamspam
```

リストの反復にも使えるが、トラブルを招きやすいので慣れないうちは避けた方が良いだろう。
定型句だと思ってリスト内包表記を使った方がバグが出にくい。


###アスタリスク `**`
```Python:ex_f2.py
def compute_square(base):
    return base ** 2
```

ただのべき乗。Pythonでは`^`ではなく`**`を使う。
平方根を求める際、math.sqrtなんて持ち出さずとも `n ** .5` で済むことは知っておくと便利。

###アスタリスク `*=`, `**=`
```Python:ex_f3.py
n = 10
n *= 3
print(n)   # 30

m = 5
m **= 3
print(m)   # 125
```

**累算代入文**と呼ばれ、意味としては`n = n * 3`及び`m = m ** 3`と一緒[^2]。
他言語でも広く使われる記法である。

[^2]: 常に同じ挙動が約束されているわけではない。

## 文字列

Pythonの文法に直結するものでは無いが、プログラミング初学者向けに追記する。

###globパターン内のアスタリスク `*`, `**`

カレントディレクトリ直下に置かれたtxtファイルのファイル名を全て取得したいとする。
その場合、globモジュールを利用して次のように書くことができる。

```Python:ex_g1.py
import glob

txt_filenames = glob.glob('*.txt')
print(txt_filenames)
```

このアスタリスクは**ワイルドカード**として用いられ、任意長の文字列にマッチする。
なお　`**/*.txt`　と書くと再帰的な探索ができるが、これについては割愛。

**参考：**

- [glob --- Unix 形式のパス名のパターン展開 — Python 3.7.4 ドキュメント](https://docs.python.org/ja/3/library/glob.html)
- [グロブ - Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AD%E3%83%96)

###正規表現内のアスタリスク `*`

文字列に対して柔軟なマッチを行いたい場合、**正規表現**が有用である。
Pythonはreモジュールで正規表現に依るマッチ／探索を提供する。

`*` は直前のパターンの繰り返しを表現する、**量指定子**の一種として用いられている。
例えば、次のようなマッチが可能である。

```Python:ex_g2.py
import re

for e in ['わ', 'わああ', 'わお', 'じゃああ', 'わあ']:
    # rって何？という人は、raw文字列について調べると良い。
    m = re.fullmatch(r'わあ*', e)
    if m:
        # 同様にfって何？という人は、フォーマット済み文字列リテラルについて調べると良い。
        print(f'{e}は悲鳴です。')   
```

**実行結果**

```txt
わは悲鳴です。
わああは悲鳴です。
わあは悲鳴です。
```

正規表現 `わあ*` は、**文字『わ』と、それに続く任意長(0文字でも可)の『あ』**にマッチする。

**参考：**

- [re --- 正規表現操作 — Python 3.7.4 ドキュメント](https://docs.python.org/ja/3/library/re.html)
- [正規表現 - Wikipedia](https://ja.wikipedia.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE)

###注意： ワイルドカードと量指定子の混同

グロブのワイルドカード `*` は、正規表現 `.*` に相当する。
例えば `abc*` がそれぞれどんな文字列にマッチするか考えてみると良い。