子类列表

时间:2009-06-09 14:35:48

标签: python

我想创建一个DataSet类,它基本上是一个样本列表。 但我需要覆盖DataSet的每个插入操作。

有没有简单的方法可以在不编写自己的追加,扩展,iadd等的情况下执行此操作?

UPDATE:我想为每个样本添加一个backpointer,在DataSet中保存样本的索引。这是我使用的处理算法所必需的。我有一个解决方案,但似乎不太优雅 - 一个renumber()函数 - 它确保后退指针有效。

1 个答案:

答案 0 :(得分:5)

我不知道如何做你所要求的事情 - 在没有覆盖它们的情况下覆盖变异器。但是,使用类装饰器,您可以“自动化”覆盖版本(假设每个版本都可以通过在基类中包装相应的方法来实现),所以它不是太糟糕......

假设您要执行的操作是添加“已修改”标志,如果自上次调用.save后数据可能已更改,则为true(您的方法会保留数据并设置{ {1}}为假)。

则...

self.modified

这种语法需要Python 2.6或更高版本,但是,在早期的Python版本中(仅支持def wrapMethod(cls, n): f = getattr(cls, n) def wrap(self, *a): self.dirty = True return f(self, *a) return wrap def wrapListMutators(cls): for n in '''__setitem__ __delitem__ __iadd__ __imul__ append extend insert pop remove reverse sort'''.split(): f = wrapMethod(cls, n) setattr(cls, n, f) return cls @wrapListMutators class DataSet(list): dirty = False def save(self): self.dirty = False 语句上的装饰器,而不支持def语句;或者甚至是不支持它们的旧版本所有的装饰者,你只需要将最后一部分(class语句)改为:

class

IOW,整洁的装饰器语法只是在普通函数调用之上的少量语法糖,它将类作为参数并重新分配。

修改:现在您已经修改了问题以澄清您的确切要求 - 在每个项目上维护一个字段class DataSet(list): dirty = False def save(self): self.dirty = False DataSet = wrapListMutators(DataSet) ,以便对所有bpi - 更容易衡量各种方法的利弊。

您可以调整我绘制的方法,但在调用包装方法之前,不是theset[i].bp == i赋值,而是在它之后进行self.dirty调用,即:

self.renumber()

这符合您声明的要求,但在许多情况下,它会做更多的工作而不是必要的工作:例如,当您def wrapMethod(cls, n): f = getattr(cls, n) def wrap(self, *a): temp = f(self, *a) self.renumber() return temp return wrap 一个项目时,这会不必要地“重新编号”所有现有的项目(以相同的值已经完成有)。但是,任何完全自动化的方法如何“知道”哪些项目(如果有的话)必须重新计算append,而不需要.bp努力?至少它必须查看它们中的每一个(因为你不想单独编码,例如,O(N) vs append& c),而且它已经是insert

所以这只有在列表的每次更改都可以O(N)时才可以接受(基本上只有当列表总是保持较小和/或不经常更改时)。

更有成效的想法可能是不是一直保持O(N)值,而只是在需要时“及时”。使.bp成为一个(只读)属性,调用一个方法来检查容器是否“脏”(使用我已经给出的自动代码维护容器中的“脏”标志)并且仅然后重新编号容器(并将其“脏”属性设置为bp)。

当列表通常受到一系列变化的影响时,这将很有效,然后才需要访问项目“False一段时间,然后再进行另一组更改等。”之间的突发交替在现实世界的容器中改变和阅读并不罕见,但只有你知道它是否适用于你的特定情况!

为了获得超出此范围的性能,我认为您需要在这种通用方法之上进行一些手动编码,以利用频繁的特殊情况。例如,可能经常调用bp,并且在特殊情况append中要完成的工作量非常小,因此编写这两行或三行可能值得您花些时间代码(不为那种情况设置脏位)。

一个警告:如果任何项目在列表中出现两次,那么任何方法都不会起作用(事实上你的要求会变得自相矛盾) - 除非你采取预防措施以避免它(你可以在{中轻松诊断),这当然是完全可能的。 {1}} - 通过保留已经看到的一组元素并在任何重复上引发异常 - 如果这对你来说不是太晚;那么“在运行中”更难诊断,即在发生突变时重复,如果这是你需要的)。也许你可以放松你的要求,这样,如果一个项目出现两次,那就没关系,append可以只指出其中一个指数;或者将renumber放入元素所在的索引的中(这也可以为从元素中获取bp的情况提供一个平滑的方法在列表中)。等等;我建议您考虑(和文档!)所有这些角落案例的深度 - 在演出前的正确性!