390
296

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2018-03-10

前書き

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

関数を呼び出すとき

アスタリスク *

ex_a1.py
my_list = [1, 2, 3]
print(*my_list)
実行結果
1 2 3

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

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

アスタリスク **

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

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

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

関数を定義するとき

アスタリスク * (仮引数名アリ)

ex_b1.py
def compute_product(*nums):
    ret = 1
    for num in nums:
        ret *= num
    return ret

print(compute_product(1, 2, 3))
実行結果
6

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

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

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な方のコードを実行してしまうと、次のような例外が発生する。

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

アスタリスク * (仮引数名ナシ)

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な方のコードを実行してしまうと、次のような例外が発生する。

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

アスタリスク **

ex_b4.py
def useless_func(**kwargs):
    print(kwargs)

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

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

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

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

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

代入文で用いられるアスタリスク *

ex_c1.py
a, b, *other = [1, 2, 3, 4, 5]
print(a, b, other)
実行結果
1 2 [3, 4, 5]

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

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

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)

リストを定義するときのアスタリスク *

ex_d1.py
list1 = [1, 2, 3]
list2 = [9, 8, 7]

my_list = [*list1, *list2]
print(my_list)
実行結果
[1, 2, 3, 9, 8, 7]

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

辞書を定義するときのアスタリスク **

ex_e1.py
fruit_dict = {'リンゴ': 'apple', 'オレンジ': 'orange'}
vegetable_dict = {'キュウリ': 'cucumber', 'にんじん': 'carrot'}

food_dict = {**fruit_dict, **vegetable_dict}
print(food_dict)
実行結果
{'リンゴ': 'apple', 'オレンジ': 'orange', 'キュウリ': 'cucumber', 'にんじん': 'carrot'}

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

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

式と式の間

###アスタリスク *

ex_f1.py
def triple(a):
    return 3 * a

ただの掛け算。
気を付ける点があるとすれば、NumPyではアダマール積に用いられていることくらい。

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

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

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

###アスタリスク **

ex_f2.py
def compute_square(base):
    return base ** 2

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

###アスタリスク *=, **=

ex_f3.py
n = 10
n *= 3
print(n)   # 30

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

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

文字列

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

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

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

ex_g1.py
import glob

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

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

参考:

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

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

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

ex_g2.py
import re

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

実行結果

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

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

参考:

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

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

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

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

390
296
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
390
296

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?