読者です 読者をやめる 読者になる 読者になる

CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: シーケンスアンパックについて

Python では、右辺がタプルなどのとき、左辺に複数の変数を置くことで、その中身を展開できる。 これをシーケンスアンパック (sequence unpack) という。

シーケンスアンパックを試してみる

まずは python コマンドを実行して REPL を起動しておこう。

$ python

例えば example という変数にタプルで 3 つの要素を代入しておく。

>>> example = (1, 2, 3)

これを右辺に置いて、左辺には同じ数の変数 a b c をカンマ区切りで置く。

>>> a, b, c = example

するとタプルの中身が、各変数に代入される。 これがシーケンスアンパックの挙動だ。

>>> a
1
>>> b
2
>>> c
3

シーケンスアンパックできるオブジェクト・できないオブジェクト

シーケンスアンパックは、例えばリストでもできる。

>>> example = [1, 2, 3]
>>> a, b, c = example
>>> a
1
>>> b
2
>>> c
3

シーケンスアンパックできるか否かは、そのオブジェクトがイテラブル (Iterable) か否かによる。 例えば object クラスのインスタンスはイテラブルでないので、シーケンスアンパックできない。

>>> a, b, c = object()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'object' object is not iterable

ユーザ定義クラスでシーケンスアンパックできるようにする

次は、ユーザ定義クラスでシーケンスアンパックできるようにしてみよう。 これは、ようするにそのユーザ定義クラスのインスタンスをイテラブルにするということ。

ユーザ定義クラスをイテラブルにするには、イテレータプロトコルという特殊メソッドを実装する必要がある。 これは具体的には __iter__() と __next__() という、ふたつのメソッドだ。 ただし、イテレータのコンテナオブジェクトであれば、このうち __iter__() さえあればいい。 コンテナオブジェクトというのは、自身のメンバなどを元にイテレータオブジェクトを生成して返すオブジェクトのことをいう。

次のサンプルコードでは User クラスをイテラブルにすることでシーケンスアンパックできるようにしている。 具体的には __iter__() メソッドを実装することで、クラスをイテレータのコンテナオブジェクトにしている。 このメソッドの中では、自身のメンバである name と age をリストにラップした上で iter() 組み込み関数でイテレータオブジェクトを取り出して返している。

>>> class User(object):
...     def __init__(self, name, age):
...         self.name = name
...         self.age = age
...     def __iter__(self):
...         return iter([self.name, self.age])
...

それでは、上記のクラスをインスタンス化しよう。

>>> u = User('Spam', 20)

そして、右辺に上記のインスタンスを、左辺は name と age という変数でそれを受ける。

>>> name, age = u

すると、シーケンスアンパックされて各変数に内容が代入された。

>>> name
'Spam'
>>> age
20

ばっちり。

まとめ

  • タプルやリストの内容を複数の変数に一度に代入することをシーケンスアンパックという
  • シーケンスアンパックできるオブジェクトはイテラブルなオブジェクト
  • ユーザ定義クラスをイテラブルにするにはイテレータプロトコルを実装する

参考

5. データ構造 — Python 3.5.2 ドキュメント