Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Python の * 演算子 (iterable unpacking operator) の使い方

More than 1 year has passed since last update.

Python の * 演算子 (iterable unpacking operator) の使い方まとめ
# Python 3.6.x を想定

まとめ

  • *iterable を評価すると,iterable の中身をバラすことができる
  • 代入文の左辺 or 仮引数に *var を置くと,var で「残り全部」を受け取ることができる
>>> *(1,2,3), 4
(1, 2, 3, 4)
>>> first, *rest = (1,2,3,4)    # first = 1, rest = [2,3,4]
>>> first, *rest = *(1,2,3), 4  # first = 1, rest = [2,3,4]

>>> def func(a, *args):
...     print(a)
...     print(args)
>>> func(0, 1, 2)
0
(1, 2)
>>> func(*range(3))
0
(1, 2)

以下詳細.

評価時(右辺値)

  • *iterable を評価すると,iterable の中身をバラすことができる.
  • 利用できる文脈:
    • タプル,リスト,セットをリテラルで生成する.
    • 関数に引数群を渡す.
    • (ほかの文脈,たとえば内包表記では使うことができない.)

タプル,リスト,セットをリテラルで生成する

(), [], {} を用いてタプル,リスト,セットをリテラルで生成する際,*iterableiterable の中身をバラして“代入”できる.

>>> (*(1,2), 3, *[4], *range(3))
(1, 2, 3, 4, 0, 1, 2)
>>> [*(1,2), 3, *[4], *range(3)]
[1, 2, 3, 4, 0, 1, 2]
>>> {*(1,2), 3, *[4], *range(3)}
{0, 1, 2, 3, 4}
>>> *(1,2), 3, *[4], *range(3)
(1, 2, 3, 4, 0, 1, 2)

補足:式のリスト
なお,最後の例は() を省略したタプルの生成記法であり,式のリスト (“tuple packing”) と呼ばれる.式のリストでシングルトンの(要素がひとつの)タプルを生成したい場合は,() を用いるときと同様,末尾に , を置く.

# tuples
>>> (1,2)
(1, 2)
>>> (1,) # singleton
(1,)
>>> (1) 
1

# expression lists generating tuples
>>> 1,2
(1, 2)
>>> 1, # singleton
(1,)
>>> 1
1

# iterable unacking in singleton
>>> (*'ab',)
('a', 'b')
>>> (*'ab')
SyntaxError: cant use starred expression here

>>> *'ab',
('a', 'b')
>>> *'ab'
SyntaxError: cant use starred expression here

関数に引数群を渡す

iterable から x, y, z を順に取り出せるとき,func(*iterable)func(x,y,z) と等価.

>>> def func(x,y,z):
...     return x + y + z

>>> func(1,3,5)
9
>>> t = (1,3,5)
>>> func(*t)
9
>>> func(1, *(3,5))
9

>>> func(t)
TypeError: func() missing 2 required positional arguments: 'y' and 'z'

可変長引数を受け取る関数の場合も同様.

>>> print('foo', 2, True)
foo 2 True

>>> print(*[1,2,3])
1 2 3
>>> print(*'abc')
a b c
>>> print(*(x**2 for x in range(5)))
0 1 4 9 16

>>> print(*'abc', True, *range(3))
a b c True 0 1 2

代入時(左辺値)

  • *var に代入すると,var が「残り全部」が受け取ることになる.
  • 利用できる文脈:
    • 代入文左辺の「変数リスト」内でイテラブルの一部を受け取る.
    • 可変長引数を受け取る関数を作る.

代入文左辺の「変数リスト」内でイテラブルの一部を受け取る

代入文の左辺にカンマ区切りの「変数リスト」を置くと,右辺のイテラブルの中身が順に左辺の変数たちに代入される.
変数リストは ()[] で囲まれていても良い.

>>> a, b, c = (x**2 for x in range(3))
>>> a
0
>>> b
1
>>> c
4

>>> (a, b, c) = (x**2 for x in range(3)) # a=0, b=1, c=4
>>> [a, b, c] = (x**2 for x in range(3)) # a=0, b=1, c=4

代入文の左辺の「変数リスト」内に * からはじまる変数を置くと,右辺のイテラブルの「残りの要素全部」が当該の変数にリストとして代入される (extended iterable unpacking).

>>> first, *rest = range(5)
>>> first
0
>>> rest
[1, 2, 3, 4]

>>> *rest, last = range(5)
>>> rest
[0, 1, 2, 3]
>>> last
4

>>> first, *rest, last = range(5)
0
>>> rest
[1, 2, 3]
>>> last
4
>>> first, *rest, last = 'ab'
>>> first
'a'
>>> rest
[]
>>> last
'b'

式のリスト(右辺)と extended iterable unpacking(左辺)の併用:

>>> first, *rest = *(1,2,3,4), 5
>>> first
1
>>> rest
[2, 3, 4, 5]

可変長引数を受け取る関数を作る

  • * からはじまる仮引数は可変長引数を受け取ることができる.仮引数名は args とするのが慣例.
  • 当該の仮引数は,関数内部ではタプル
>>> def func(*args):
...     # `args` is a tuple
...     return args

>>> func(1, 2, 3)
(1, 2, 3)
>>> func('abc', 42, True)
('abc', 42, True)
>>> func(*'abc')
('a', 'b', 'c')

おまけ

*iterableiterable をバラしたいシーン × 2

zip(*iterable) による unzip/transpose

>>> for t in zip(range(3), 'abc'):
...     print(t)
(0, 'a')
(1, 'b')
(2, 'c')

# unzip/transpose iter_of_iter by zip(*iter_of_iter)
>>> for it in zip(*[(0, 'a'), (1, 'b'), (2, 'c')]):
...     print(it)
(0, 1, 2)
('a', 'b', 'c')

iterable unpacking は内包表記では使うことができない

>>> [*it for it in [[0,1,2], [3], [4,5]]]
SyntaxError: iterable unpacking cannot be used in comprehension

# cf.
>>> def flatten(iter_of_iter):
...     "Flatten one level of nesting"
...     # via. itertools recipes
...     # https://docs.python.org/ja/3/library/itertools.html
...     return itertools.chain.from_iterable(iter_of_iter)
>>> list(flatten([[0,1,2], [3], [4,5]]))
[0, 1, 2, 3, 4, 5]

参考資料

eumesy
自然言語処理を専攻する大学院生です
https://twitter.com/sho_yokoi/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away