子类列表

Ant*_*kov 4 python

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

有没有简单的方法可以做到这一点,而无需编写自己的追加,扩展,iadd等?

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

Ale*_*lli 5

我不知道你在做什么的方式 - 覆盖变异器而不是覆盖它们.但是,使用类装饰器,您可以"自动化"覆盖版本(假设每个版本都可以通过在基类中包装相应的方法来实现),所以它并不太糟糕......

例如,假设您要执行的操作是添加"已修改"标志,如果自上次调用以来数据可能已更改,则为true .save(保留数据并设置self.modified为False的方法).

然后...:

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
Run Code Online (Sandbox Code Playgroud)

这种语法需要Python 2.6或更高版本,但是,在早期的Python版本中(仅支持def语句上的装饰器,而不支持class语句;或者甚至是根本不支持装饰器的非常老版本),您只需要更改最后一个版本部分(class声明),以:

class DataSet(list):
  dirty = False
  def save(self): self.dirty = False
DataSet = wrapListMutators(DataSet)
Run Code Online (Sandbox Code Playgroud)

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

编辑:现在您已经编辑了您的问题以阐明您的确切要求 - 在每个项目上维护一个字段,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
Run Code Online (Sandbox Code Playgroud)

这符合您所陈述的要求,但在许多情况下,它将完成远远超出必要的工作:例如,当您处理append某个项目时,这会不必要地"重新编号"所有现有项目(与已有的相同值).但是,任何完全自动化的方法怎么能"知道"哪些项目,如果有的话,它必须重新计算.bp,而不O(N)费力?至少它必须查看它们中的每一个(因为你不想单独编码,例如appendvs insert&c),而且已经存在O(N).

因此,只有当列表的每个单独更改都可以接受时O(N)(基本上只有列表始终保持较小和/或不经常更改)才能接受.

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

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

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

一个警告:如果任何项目在列表中出现两次,那么任何方法都不会起作用(事实上你的要求会变得自相矛盾) - 除非你采取预防措施以避免它(你可以很容易地renumber通过保持它来诊断它),这当然是完全可能的.已经看到的一组元素,并且对任何重复都提出了例外 - 如果这对你来说不是太晚;它很难在"飞行中"进行诊断,即在导致重复的突变时,如果这是你需要的).也许你可以放松你的要求,这样,如果一个项目出现两次,那就没关系,bp只能指出其中一个指数; 或者将元素存在的bp索引(这也可以为从不在列表中bp的元素获取的情况提供平滑的方法).等等; 我建议您考虑(并记录!)所有这些角落案例的深度 - 表现之前的正确性!