Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/301.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 子类列表_Python - Fatal编程技术网

Python 子类列表

Python 子类列表,python,Python,我想创建一个DataSet类,它基本上是一个示例列表。 但是我需要覆盖数据集的每个插入操作 有没有一种简单的方法可以做到这一点,而不用编写我自己的append、extend、iadd等 更新:我想向每个样本添加一个反向指针,保存数据集中样本的索引。这是我使用的处理算法所需要的。我有一个解决方案,但它似乎是不合法的——一个renumber()函数——它确保了反向指针是有效的。我不知道有什么方法可以满足您的要求——在不重写它们的情况下重写变式。但是,使用类装饰器,您可以“自动化”覆盖版本(假设每个版

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

有没有一种简单的方法可以做到这一点,而不用编写我自己的append、extend、iadd等


更新:我想向每个样本添加一个反向指针,保存数据集中样本的索引。这是我使用的处理算法所需要的。我有一个解决方案,但它似乎是不合法的——一个renumber()函数——它确保了反向指针是有效的。

我不知道有什么方法可以满足您的要求——在不重写它们的情况下重写变式。但是,使用类装饰器,您可以“自动化”覆盖版本(假设每个版本都可以通过在基类中包装相应的方法来实现),所以这并不太糟糕

例如,假设您要做的是添加一个“modified”标志,如果自上次调用
.save
(您的一种方法,它保存数据并将
self.modified
设置为False)以来数据可能已更改,则为true

然后…:

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
这种语法需要Python2.6或更高版本,但是,在早期的Python版本中(只支持
def
语句上的decorator,不支持
class
语句上的decorator;甚至是非常旧的不支持decorators的),您只需要将最后一部分(
class
语句)更改为:

注意,整洁的decorator语法只是普通函数调用之上的一小部分语法糖,该函数调用将类作为参数并重新分配它

编辑:现在您已经编辑了您的问题以澄清您的确切要求——在每个项目上保留一个字段
bp
,这样,对于所有
i
set[i].bp==i
——就更容易权衡各种方法的利弊

您可以调整我所绘制的方法,但在调用包装方法之前,您可以在其之后调用
self.renumber()
调用,而不是
self.dirty
赋值,即:

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

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

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

当列表通常会发生突发性更改时,这将很好地发挥作用,只有这样,您才需要访问项目“
bp
”一段时间,然后再进行一系列更改,等等。在现实世界的容器中,这种更改和读取之间的突然交替并不罕见,但只有您才能知道它是否适用于您的特定情况

为了获得更高的性能,我认为您需要在这种通用方法的基础上进行一些手动编码,以利用频繁的特殊情况。例如,
append
可能经常被调用,而在特殊情况下
append
要做的工作量非常小,因此编写这两行或三行代码(不设置该情况下的脏位)可能非常值得


一个警告:如果列表中有任何项目出现两次,那么任何方法都不起作用(事实上,您的需求变得自相矛盾)——当然,这是完全可能的,除非您采取预防措施避免它(你可以在
重新编号
中轻松诊断它——保持一组已经看到的元素,并在任何复制上引发异常——如果这对你来说还不算太晚的话;如果你需要的话,“即时”诊断就更难了,即在导致复制的突变发生时)。也许您可以放宽您的要求,这样,如果一个项目出现两次,就可以了,
bp
可以只指示其中一个索引;或者将
bp
设置为元素出现的一组索引(这也将提供一个平滑的方法来从< <强> > < <强> >列表中的元素中获得<代码> BP<代码>等;我建议您仔细考虑(和<强>文档< /强>!)所有这些角落案例深度-性能前的正确性!

您确定吗,亚历克斯?Uslist的文档称:注意:此模块仅适用于向后兼容。如果您编写的代码不需要在Python 2.2之前使用Python版本,请直接从内置列表类型考虑子类。“@Janet,是的,我说错了,所以我编辑了答案,谢谢。不客气!我刚刚添加了很多关于您具体案例的讨论,所以我建议您在当前状态下重新阅读答案(tx接受了之前不完整的形式tho;-).如果需要更多的讨论或代码,我建议你打开一个新的问题tho,因为这已经是我给出的最长的答案了(tx提出了如此有趣的问题,顺便说一句!).正如Alex回答的那样,这似乎很难。但是如果你向我们解释应该如何进行覆盖插入,也许人们可以想出一个优雅的解决方案。我想他指的是猴子修补。@NicDumZ:我已经更新了这个问题
def wrapMethod(cls, n):
    f = getattr(cls, n)
    def wrap(self, *a):
      temp = f(self, *a)
      self.renumber()
      return temp
    return wrap