rog*_*rog 13 python subclass instance-variables set
我正在实现一个几乎与集合相同的对象,但需要一个额外的实例变量,所以我是内置集合对象的子类.在复制其中一个对象时,确保复制此变量的值的最佳方法是什么?
使用旧的set模块,以下代码完美地运行:
import sets
class Fooset(sets.Set):
def __init__(self, s = []):
sets.Set.__init__(self, s)
if isinstance(s, Fooset):
self.foo = s.foo
else:
self.foo = 'default'
f = Fooset([1,2,4])
f.foo = 'bar'
assert( (f | f).foo == 'bar')
Run Code Online (Sandbox Code Playgroud)
但是使用内置的设置模块不起作用.
我能看到的唯一解决方案是覆盖返回复制的set对象的每个方法...在这种情况下,我可能不会打扰子类化set对象.当然有一种标准的方法可以做到这一点?
(为了澄清,下面的代码并不能正常工作(断言失败):
class Fooset(set):
def __init__(self, s = []):
set.__init__(self, s)
if isinstance(s, Fooset):
self.foo = s.foo
else:
self.foo = 'default'
f = Fooset([1,2,4])
f.foo = 'bar'
assert( (f | f).foo == 'bar')
Run Code Online (Sandbox Code Playgroud)
)
Mat*_*all 17
我最喜欢的包装内置集合方法的方法:
class Fooset(set):
def __init__(self, s=(), foo=None):
super(Fooset,self).__init__(s)
if foo is None and hasattr(s, 'foo'):
foo = s.foo
self.foo = foo
@classmethod
def _wrap_methods(cls, names):
def wrap_method_closure(name):
def inner(self, *args):
result = getattr(super(cls, self), name)(*args)
if isinstance(result, set) and not hasattr(result, 'foo'):
result = cls(result, foo=self.foo)
return result
inner.fn_name = name
setattr(cls, name, inner)
for name in names:
wrap_method_closure(name)
Fooset._wrap_methods(['__ror__', 'difference_update', '__isub__',
'symmetric_difference', '__rsub__', '__and__', '__rand__', 'intersection',
'difference', '__iand__', 'union', '__ixor__',
'symmetric_difference_update', '__or__', 'copy', '__rxor__',
'intersection_update', '__xor__', '__ior__', '__sub__',
])
Run Code Online (Sandbox Code Playgroud)
基本上你在自己的答案中做的事情是一样的,但是用较少的loc.如果你想用列表和dicts做同样的事情,也很容易放入元类.
我认为,推荐的方法不是直接从内置方法继承子类set,而是利用collections中可用的Abstract Base ClassSet。
使用ABC套装免费送您一些方法作为一个mix-in,所以你可以只定义一个最小集合类__contains__(),__len__()和__iter__()。如果您想要一些更好的set方法,例如intersection()和difference(),则可能必须包装它们。
这是我的尝试(该尝试恰好是一个Frozenset样的,但您可以从中继承MutableSet以获取可变版本):
from collections import Set, Hashable
class CustomSet(Set, Hashable):
"""An example of a custom frozenset-like object using
Abstract Base Classes.
"""
___hash__ = Set._hash
wrapped_methods = ('difference',
'intersection',
'symetric_difference',
'union',
'copy')
def __repr__(self):
return "CustomSet({0})".format(list(self._set))
def __new__(cls, iterable):
selfobj = super(CustomSet, cls).__new__(CustomSet)
selfobj._set = frozenset(iterable)
for method_name in cls.wrapped_methods:
setattr(selfobj, method_name, cls._wrap_method(method_name, selfobj))
return selfobj
@classmethod
def _wrap_method(cls, method_name, obj):
def method(*args, **kwargs):
result = getattr(obj._set, method_name)(*args, **kwargs)
return CustomSet(result)
return method
def __getattr__(self, attr):
"""Make sure that we get things like issuperset() that aren't provided
by the mix-in, but don't need to return a new set."""
return getattr(self._set, attr)
def __contains__(self, item):
return item in self._set
def __len__(self):
return len(self._set)
def __iter__(self):
return iter(self._set)
Run Code Online (Sandbox Code Playgroud)