【问题标题】:Python list entries are overridden by last appended entryPython 列表条目被最后附加的条目覆盖
【发布时间】:2010-03-05 18:40:44
【问题描述】:

我有这个代码:

def __parse(self):        
    for line in self.lines:
        r = Record(line)
        self.records[len(self.records):] = [r]
        print self.records[len(self.records)-1].getValue() # Works fine!
    print self.record[0].getValue() # Gives the same as
    print self.record[1].getValue() # as
    # ... and so on ...
    print self.record[len(self.record)-1].getValue()

现在它应该做的是从文本行中制作记录。但是,当我在 for 循环完成后访问这些列表时,所有记录都会为我调用它们的方法提供相同的结果。当我在附加后立即访问 for 循环中的记录时,它是正确的,因此 Record init 不会出错。不,绝对可以肯定我输入的台词不同!有谁知道为什么会这样?帮助将不胜感激!

【问题讨论】:

  • 你为什么不直接做 self.records.append(r)?
  • 你能告诉我们Record是如何定义的吗?如果Recordline 存储为类属性而不是实例属性,那么这可能可以解释问题。
  • 您只检查循环中的最新记录。以前的值呢?

标签: python list append


【解决方案1】:

Ahue,您在 shared 类命名空间中有可变对象——在开始使用 python 时这是一个非常常见的误解。将CsvSetrecords = []的初始化移入其__init__函数,将record = {}移入Record__init__函数。应该如下所示:

class Record:
    def __init__(self,lines):
        self.record = {}
        self.__parse()

class CsvSet:
    def __init__(self,lines):
        self.records = []
        self.__parse()

当您在类区域中声明一个可变变量时,它在这些类的所有实例之间共享,而不是为每个实例创建。通过将初始化移动到实例方法(在本例中为 __init__),您正在为每个实例创建新的可变存储,这正是您的意图。

【讨论】:

  • 非常感谢。我认为这就像在 Java 中一样。现在它似乎工作了!
【解决方案2】:

如果你用以下替换它仍然会发生:

self.record = [Record(l) for l in self.lines]

编辑:

Record一定有些错误,因为那里的代码确实有效,即使它让有经验的编码人员在阅读时哭泣。

【讨论】:

  • 我也认为是 Record() 类被破坏了。我真的很想知道它是如何实现的……看到self.records[len(self.records):] = [r] (有效!)代码我猜它也可能是“聪明”的东西:)在可变结构与不可变结构混淆的情况下会发生类似的问题(覆盖一些“其他”数据)例如使用列表作为默认参数时。
【解决方案3】:

你没有附加到self.records;你总是覆盖它。

用途:

self.records.append(r)

改为。

编辑:没关系。请参阅 Ignacio Vasquez-Abrams 的评论。如果不是这样,我会删除这个答案。

【讨论】:

  • 其实L[len(L):] = [X]是一种病态的追加形式。
  • 这是一个相当不错的混淆。
【解决方案4】:

记录等级被打破。您使用类变量 (Record.record) 而不是实例属性。类变量对所有实例都是一个,您希望每个实例使用不同的self.record

移动:

record = {}
line = ""

构造函数中的行(在def __init__(self,line):下缩进)

【讨论】:

    【解决方案5】:

    Record 类已损坏,您总是返回相同的对象。

    没有看到 Record 的代码是不可能猜到的

    也许您使用列表或字典作为__init__ 的默认参数,并使用getValue() 返回。

    另一种可能性是getValue() 返回的是类属性而不是实例属性

    【讨论】:

      【解决方案6】:

      好的,所以我也将发布 Record 类的代码以进行澄清。

      课堂记录:

      record = {}
      line = ""
      
      def __init__(self,line):
          self.line = line 
          self.__parse()
      
      def __parse(self):
          fieldnames = ['from','to','value','error']
          fields = self.line.split(',')
      
          c = 0
          for field in fields:
              self.record[fieldnames[c]] = field.strip()
              c+=1
      
          self.record['from'] = datetime.datetime.strptime(self.record['from'],"%Y-%m-%d")
          self.record['to'] = datetime.datetime.strptime(self.record['to'],"%Y-%m-%d")
      

      类 CsvSet:

      records = []
      
      def __init__(self,lines):
          self.__parse()
      
      def __parse(self):        
          for line in self.lines:
              self.records.append(Record(line))
      

      CsvSet 中的 __parse 方法现在是一开始的样子。如果出于调试原因,我进行了更改,但结果是相同的。 Ignacio,你说得对,我两周前才开始使用 Python...

      【讨论】:

      • 您应该编辑您的原始问题,而不是将其添加为答案。
      • 谢谢,我下次再做。对不起!
      猜你喜欢
      • 1970-01-01
      • 2018-05-02
      • 2018-12-21
      • 2016-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-09
      相关资源
      最近更新 更多