34
26

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-04-23

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]

参考資料

34
26
2

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
34
26