私は次のように読んでいる質問に答えようとしています:「「セット」の演算子の戻り値をセットのサブクラスのタイプにする方法。私の読みが正しければ、重複する自分の質問からここに来ました。
この回答は、次のように他の回答とは異なります。
- 指定されたクラス (サブクラス) は、デコレータを追加することによってのみ変更されます
- したがって、指定されたクラス (hasattr(s, 'foo')) の詳細を気にしないほど一般的です。
- 追加コストは、すべてのインスタンスに対してではなく、クラス (装飾されたとき) ごとに 1 回支払われます。
- 「セット」に固有の特定の例の唯一の問題は、簡単に定義できるメソッドのリストです。
- 基本クラスは抽象ではなく、それ自体をコピー構築できると仮定します (そうでない場合は、基本クラスのインスタンスからコピーする __init__ メソッドを実装する必要があります)。
プロジェクトまたはモジュールのどこにでも配置できるライブラリ コード:
class Wrapfuncs:
def __init__(self, *funcs):
self._funcs = funcs
def __call__(self, cls):
def _wrap_method(method_name):
def method(*args, **kwargs):
result = getattr(cls.__base__, method_name)(*args, **kwargs)
return cls(result)
return method
for func in self._funcs:
setattr(cls, func, _wrap_method(func))
return cls
セットで使用するには、新しいインスタンスを返すメソッドのリストが必要です。
returning_ops_funcs = ['difference', 'symmetric_difference', '__rsub__', '__or__', '__ior__', '__rxor__', '__iand__', '__ror__', '__xor__', '__sub__', 'intersection', 'union', '__ixor__', '__and__', '__isub__', 'copy']
クラスで使用できます。
@Wrapfuncs(*returning_ops_funcs)
class MySet(set):
pass
このクラスの何が特別なのか、詳細は割愛します。
次の行でコードをテストしました。
s1 = MySet([1, 2, 3])
s2 = MySet([2, 3, 4])
s3 = MySet([3, 4, 5])
print(s1&s2)
print(s1.intersection(s2))
print(s1 and s2)
print(s1|s2)
print(s1.union(s2))
print(s1|s2|s3)
print(s1.union(s2, s3))
print(s1 or s2)
print(s1-s2)
print(s1.difference(s2))
print(s1^s2)
print(s1.symmetric_difference(s2))
print(s1 & set(s2))
print(set(s1) & s2)
print(s1.copy())
どの印刷:
MySet({2, 3})
MySet({2, 3})
MySet({2, 3, 4})
MySet({1, 2, 3, 4})
MySet({1, 2, 3, 4})
MySet({1, 2, 3, 4, 5})
MySet({1, 2, 3, 4, 5})
MySet({1, 2, 3})
MySet({1})
MySet({1})
MySet({1, 4})
MySet({1, 4})
MySet({2, 3})
{2, 3}
MySet({1, 2, 3})
結果が最適でない場合が 1 つあります。これは、演算子がクラスのインスタンスを右側のオペランドとして使用し、組み込みの「セット」のインスタンスを最初として使用する場合です。私はこれが好きではありませんが、この問題は私が見たすべての提案された解決策に共通していると思います.
collections.abc.Set が使用されている例を提供することも考えています。それは次のように行うことができますが:
from collections.abc import Set, Hashable
@Wrapfuncs(*returning_ops_funcs)
class MySet(set, Set):
pass
@bjmcが念頭に置いていた利点があるのか 、それとも「無料」で提供される「いくつかの方法」が何であるかはわかりません。このソリューションは、基本クラスを使用して作業を行い、サブクラスのインスタンスを返すことを目的としています。メンバーオブジェクトを使用して作業を行うソリューションは、おそらく同様の方法で生成できます。