Today(※最近) I learnedな小ネタです
目次
Pythonのitertools.chainで混乱しがち
先日書いた、ネストしたfor文を全部抜けるにはジェネレータを使うという話
ジェネレータ関数を自前で定義する代わりに、itertools.chain.from_iterable()も取り上げました。
2重のリストから1, 2, 3, 4, と1つずつ取り出すイテレータを作っています。
from itertools import chain for element in chain.from_iterable([[1, 2], [3, 4], [5, 6]]): print(element) if element == 3: break
itertools.chain.from_iterable()の他に、itertools.chain()もあり、「これってそれぞれどう呼び出すんだっけ?」と混乱しがちなので、今回向き合います。
itertools.chainはクラス
まずitertools.chainはクラスです。
>>> # この記事では Python 3.12.6 >>> import itertools >>> type(itertools.chain) <class 'type'> >>> type(str) <class 'type'> >>> class C: ... >>> type(C) <class 'type'>
これを知ったことで、私はitertools.chain()とitertools.chain.from_iterable()に向き合いやすくなりました
itertools.chain:イニシャライザ(__init__)itertools.chain.from_iterable():インスタンスを返すクラスメソッド
itertoolsのドキュメントより、引数のシグネチャ
ドキュメントから、それぞれの引数のシグネチャを確認します
itertools.chain(*iterables)- イテラブル1を可変長個(=何個でも)受け取ります
itertools.chain([1, 2], [3, 4], [5, 6])のような初期化になりますね- 3つのイテラブルを渡しています
itertools.chain.from_iterable(iterable)- たった1つのイテラブルを受け取ります
- 初期化は
itertools.chain.from_iterable([[1, 2], [3, 4], [5, 6]])- 渡したイテラブルは1つです
- 中の要素にイテラブルを持っていますね
ここまでに確認したことから、以下のように書けます
- 1例目:1つのイテラブルを
itertools.chain.from_iterable()に渡します - 2例目:複数のイテラブルを
itertools.chain()に渡します - 3例目
- イテラブルのイテラブルであることを利用した例です
- イテラブルのイテラブルを
*でアンパックして、複数のイテラブルをitertools.chain()に渡しています
終わりに
混乱していたitertools.chain()とitertools.chain.from_iterable()の呼び出し方を完全に理解しました!
itertools.chainはクラスitertools.chain()はイニシャライザで、任意個のイテラブルを受け取るitertools.chain.from_iterable()はクラスメソッドで、イテラブルのイテラブル1つを受け取る- 1つのイテラブルから だから
from_iterableという命名なのかも(from single iterableの意が込められている説)
- 1つのイテラブルから だから
イテラブルがいくつか手元にあるときに少ないコード量でイテレータを作れるので、2通りの呼び出し方を完全に理解したitertools.chainは役に立ちそうです
- 「イテラブル」を扱った過去記事 ↩