メソッド set.__contains__

メソッド set.__contains__ のヘルプ情報を確認します。

>>> help(set.__contains__)
Help on method_descriptor:

__contains__(...)
x.__contains__(y) <==> y in x.

これを見て、set.__contains__ は、演算子 in の動作を規定しているのが分かります。実際に、その動作を確認してみましょう。

>>> ex
set(['A', 'C', 'B'])
>>> "A" in ex
True
>>> "@" in ex
False

文字列 "A" は、集合の要素に含まれるので、True が得られます。文字列 "@" は、集合の要素に含まれないので、False が得られます。

>>> ex = set([frozenset(e) for e in "ABC"])
>>> ex
set([frozenset(['C']), frozenset(['B']), frozenset(['A'])])
>>> set("A") in ex
True
>>> set("@") in ex
False

集合の要素に「集合」を含む場合も同様です。集合 set("A") は、集合 ex の要素に含まれるので、True が得られます。集合 set("@") は、集合 ex の要素に含まれないので、False が得られます。

ソースコード:SetCollection.Contains()

(メソッド set.__contains__ に相当する)メソッド Contains の定義を含む、ソースコードの断片を次に示します。

# IronPython-1.1.2/Src/IronPython/Runtime/Set.cs
public class SetCollection : ISet, IRichComparable, IRichEquality {
Dict items;

#region ISet
[PythonName("__contains__")]
public object Contains(object o) {
// promote sets to FrozenSet's for contains checks (so we get a hash code)
o = SetHelpers.GetHashableSetIfSet(o);

Ops.Hash(o); // make sure we have a hashable item
return Ops.Bool2Object(items.ContainsKey(o));
}

クラス SetCollection のヘッダーを見ると、ここで set 型を定義しているのが分かります。

set:Decorator(dict)

そこで、目に付くのは、インスタンス属性に関する次の記述です。

    Dict items;

これを見ると(組み込み型 dict に相当する)クラス Dict のインスタンスを再利用(内包)しているのが分かります。つまり、set は dict を内包するフィルターと見なせます。すると、次のような構造が見えてきます。

    public object Contains(object o) {
...
return ... items.ContainsKey(o) ...
}

つまり、引数 o が、辞書 items のキー要素に含まれるか ContainsKey に依存することが分かります。
ここでは、メソッド ContainsKey のリターン値からどのようにして object が得られるか(how)は知らなくても、それを使ってなにをしたいか(what)を理解できれば、十分です。bool 型に相当するオブジェクトが欲しいときに、Ops.Bool2Object を利用するだけです。
次に気になるのは、SetHelpers.GetHashableSetIfSet の存在です。

ソースコード:SetHelpers.GetHashableSetIfSet()

次に気になるのは、SetHelpers.GetHashableSetIfSet の存在です。

    public static object GetHashableSetIfSet(object o) {
SetCollection asSet = o as SetCollection;
if (asSet != null) {
return FrozenSetCollection.Make(asSet.GetEnumerator());
}
return o;
}

このメソッドでは、(可能なら)引数 o と同じ要素を持つ FrozenSetCollection のインスタンスを生成して、これをリターン値とします。それ以外は、そのまま引数 o をリターン値とします。

ソースコード:SetCollection.GetEnumerator()

次に気になるのは、SetCollection.GetEnumerator の存在です。

    #region IEnumerable Members
public IEnumerator GetEnumerator() {
return items.Keys.GetEnumerator();
}

前述したように、インスタンス属性 items からは、次のように、

    public class Dict : ...
public ICollection Keys { get { ...

プロバティー Keys を介して、インターフェース ICollection の規約に従う、インスタンスが得られます。すると、次に示す典型的な C# のイディオムに沿って、

    public interface ICollection : ...
IEnumerator GetEnumerator()

インターフェース IEnumerator の規約に従う、インスタンスが得られます。つまり、SetCollection.GetEnumerator は、ICollection.GetEnumerator を利用するための、Adapter としての役割を果たします。

ソースコード:FrozenSetCollection.Make()

次に気になるのは、FrozenSetCollection.Make の存在です。

    internal static FrozenSetCollection Make(object setData) {
FrozenSetCollection fs = setData as FrozenSetCollection;
if (fs != null) {
return fs;
}
fs = new FrozenSetCollection(setData);
return fs;
}

このメソッドでは、引数 setData を FrozenSetCollection fs と見なして、そのままをリターン値とします。それ以外は、引数 setData と同じ要素を持つ FrozenSetCollection のインスタンス fs を生成して、これをリターン値とします。

ソースコード:FrozenSetCollection()

次に気になるのは、FrozenSetCollection の存在です。

    public class FrozenSetCollection : ...
Dict items;
int hashCode;

protected FrozenSetCollection(object set) {
IEnumerator setData = Ops.GetEnumerator(set);
items = new Dict();
while (setData.MoveNext()) {
object o = setData.Current;
if (!items.ContainsKey(o)) {
items.Add(o, o);
}
}
CalculateHashCode();
}