この前ソースを眺めていたら、次のようなコードがありました。
groups = set([row.group_id for row in rows]) groups_required = set([row.group_id for row in rows2]) if groups.intersection(groups_required): r = True else: r = False
このコードで if 文は何を判定しているのか、理解できなかったので調べてみました。
set クラス
Python組み込みで set 及び frozenset クラスがある。Pythonドキュメントの記述を紹介する。
set(集合)型 — set, frozenset (抜粋)set オブジェクトは順序付けされていない hashable (ハッシュ可能な) オブジェクトのコレクションです。よくある使い方には、メンバーシップのテスト、数列から重複を削除する、そして論理積、論理和、差集合、対称差など数学的演算の計算が含まれます。
バージョン 2.4 で追加.
他のコレクションと同様、 sets は x in set, len(set) および for x in set をサポートします。順序を持たないコレクションとして、 sets は要素の位置と (要素の) 挿入位置を保持しません。したがって、 sets はインデックス、スライス、その他のシーケンス的な振る舞いをサポートしません。
set および frozenset という、2つの組み込みset型があります。 set は変更可能な — add() や remove() のようなメソッドを使って内容を変更できます。変更可能なため、ハッシュ値を持たず、また辞書のキーや他のsetの要素として用いることができません。 frozenset 型はイミュータブルで、ハッシュ化可能 (hashable) です — 作成後に内容を改変できません。そのため、辞書のキーや他の集合の要素として使えます。
参考: Python 2.7ja1 documentation - 5.7. set(集合)型 — set, frozenset
一読だけでは何のことかわからない。しかし setは書き換え可能だが frozensetは改変不可、そして frozensetはハッシュ化可能で辞書のキーや他の集合の要素として使えるが、set はハッシュ値を持たないためキーや他の集合の要素としては使えないことがわかる。その他は、ほぼ同じ機能を持ったクラスのようだ。
set は重複を持たない、順序を持たない要素の集合オブジェクトということのようだ。さっそく試してみよう。
>>> spam = set('monty python') >>> spam set([' ', 'h', 'm', 'o', 'n', 'p', 't', 'y'])適当な文字列を set に渡すと、重複を排除した要素に分解することがわかる。また順序も保存していない。
>>> spam = set(['red','green','blue','red']) >>> spam set(['blue', 'green', 'red'])今度はリスト値を渡してみる。同様に重複や順序を保存しない集合値になる。
set は、いくつかの演算機能(メソッド)を持っている。これを試してみる。
>>> spam = set(['red','green','blue','red']) >>> len(spam) 3 >>> 'blue' in spam True >>> 'yellow' not in spam Truelen は要素の数をカウントして返す。in は要素に含まれるかどうか、not in は要素に含まれていないかどうかをチェックしてブール値で返す。
この他にもたくさんの演算機能がある。詳細は次のサイトを参考にしてください。
参考
Python 2.7ja1 documentation - 5.7. set(集合)型 — set, frozenset
w.koshigoe.jp - set型(集合型)
バリケンのPython日記
intersection メソッド
それでは本題の if 文に話を戻す。if 文では intersection メソッドが使われている。このメソッドは次のような説明されている。
intersection(other, ...)
set & other & ...
set と全ての other に共通する要素を持つ、新しい set を返します。
バージョン 2.6 で変更: 複数のイテラブルからの入力を受け入れるようになりました。
Python 2.7ja1 documentation - 5.7. set(集合)型 — intersection
複数の setオブジェクトから、共通する要素だけを抜き出す機能のようだ、試してみる。
>>> spam = set(['red','green','blue','cyan','magenta','yellow']) >>> ham = set(['blue','cyan','white','black']) >>> spam.intersection(ham) set(['blue', 'cyan'])
>>> spam = set(['red','green','blue','cyan','magenta','yellow']) >>> ham = set(['white','black']) >>> spam.intersection(ham) set([])
共通する要素が存在しない場合は空値になる。つまり条件式に使用する真理値は、空値やゼロは Falseとされ、それ以外の値が入ったオブジェクトは True とみなされる。
参考: Python 2.7ja1 documentation - 5.1. 真理値テスト
つまり最初に出た次のコードは、
groups = set([row.group_id for row in rows]) groups_required = set([row.group_id for row in rows2]) if groups.intersection(groups_required): r = True else: r = Falsegroups と groups_required を比べて、両方のオブジェクトに共通する要素がある(論理積)場合は r=True とし、共通の要素が存在しない場合は r=False と動作することがわかる。結構このようなロジックは使うのではないだろうか。
ちなみに intersection は次のようにアンド(&)演算子でも記述可能だ。
>>> spam = set(['red','green','blue','cyan','magenta','yellow']) >>> ham = set(['blue','cyan','white','black']) >>> spam & ham set(['blue', 'cyan'])
おまけ
最後に、setクラスを使った集合同士の論理式を示してみます。
参考: Python 2.7ja1 documentation - 5.7. set(集合)型 — set, frozenset