我想创建一个DataSet类,它基本上是一个样本列表。 但我需要覆盖DataSet的每个插入操作。
有没有简单的方法可以在不编写自己的追加,扩展,iadd等的情况下执行此操作?
UPDATE:我想为每个样本添加一个backpointer,在DataSet中保存样本的索引。这是我使用的处理算法所必需的。我有一个解决方案,但似乎不太优雅 - 一个renumber()函数 - 它确保后退指针有效。
答案 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)
,以便对所有bp
,i
- 更容易衡量各种方法的利弊。
您可以调整我绘制的方法,但在调用包装方法之前,不是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
的情况提供一个平滑的方法在列表中)。等等;我建议您考虑(和文档!)所有这些角落案例的深度 - 在演出前的正确性!