在Python中重写设置方法

2 投票
2 回答
9372 浏览
提问于 2025-04-15 15:22

我想创建一个自定义的集合,这个集合可以自动把对象转换成另一种形式,以便存储在集合里(具体背景可以参考使用Python字典作为非嵌套的键)。

如果我重写了 add(添加)、remove(移除)、__contains__(检查是否包含)、__str__(字符串表示)、update(更新)和 __iter__(迭代),这样做够不够让其他操作正常工作,还是说我还需要重写其他的东西呢?

2 个回答

1

在Python 2.6中:

import collections
print collections.MutableSet.__abstractmethods__
# prints:
# frozenset(['discard', 'add', '__iter__', '__len__', '__contains__'])

你可以创建一个新的类,让它继承自collections.MutableSet,然后重写上面提到的方法。

更新方法其实很简单,只要你实现了上面提到的基本内容。

def update(self, iterable):
    for x in iterable:
        self.add(x)
9

根据@kaizer.se的建议,从collections的抽象类入手是2.6版本中合适的解决方案(我不太明白你为什么想调用super——你想委托什么功能,为什么不通过包含而不是继承来实现呢?)。

确实,你不会得到update方法——通过提供抽象方法,你会得到__le__, __lt__, __eq__, __ne__, __gt__, __ge__, __and__, __or__, __sub__, __xor__, 和 isdisjoint(这些来自collections.Set),还有clear, pop, remove, __ior__, __iand__, __ixor__, 和 __isub__(这些来自collections.MutableSet),这比你从子类化set得到的要多得多(在子类化时,你必须重写每一个你感兴趣的方法)。你只需要提供你想要的其他集合方法。

请注意,像collections.Set这样的抽象基类与具体类(包括内置的set和(在2.6中)老旧的sets.Set,虽然已经不推荐使用但仍然存在(在Python 3中已被移除))是非常不同的。抽象基类是为了被继承而设计的(而且一旦你实现了所有的抽象方法,它们可以合成一些方法),其次是为了“注册”类,使得这些类看起来像是从它们继承的,即使实际上并不是(这样可以让isinstance更好用、更有用)。

下面是一个适用于Python 3.1和2.6的工作示例(没有理由使用3.0,因为3.1在各方面都有优势,没有劣势):

import collections

class LowercasingSet(collections.MutableSet):
  def __init__(self, initvalue=()):
    self._theset = set()
    for x in initvalue: self.add(x)
  def add(self, item):
    self._theset.add(item.lower())
  def discard(self, item):
    self._theset.discard(item.lower())
  def __iter__(self):
    return iter(self._theset)
  def __len__(self):
    return len(self._theset)
  def __contains__(self, item):
    try:
      return item.lower() in self._theset
    except AttributeError:
      return False

撰写回答