【问题标题】:python how to update json list if condition matches如果条件匹配,python如何更新json列表
【发布时间】:2013-09-17 21:46:54
【问题描述】:

对于西班牙语的代码,我很抱歉,但除此之外,你应该能够理解它的结构,我使用的是 Python 3.3.2,在这里遇到了问题。

leyendoestadisticas = open("listas\Estadisticas.txt", "r")
bufferestadisticas = leyendoestadisticas.read()
leyendoestadisticas.close()
if not '"'+user.name+'"' in bufferestadisticas: #If name is not found, do this
  escribiendoestadisticas = open("listas\Estadisticas.txt", 'a')
  escribiendoestadisticas.write(json.dumps([user.name, palabrasdelafrase, letrasdelafrase,
                                            "1", user.nameColor, user.fontColor, user.fontFace, user.fontSize, message.body, room.name])+"\n")
  escribiendoestadisticas.close()
else: #If name is found...
  data = []
  with open('listas\Estadisticas.txt', 'r+') as f:
    for line in f:
      data_line = json.loads(line)
      if data_line[0] == user.name: #if name matches...
        if data_line[9] == room.name: #And room also, then update info.
          data_line[1] = int(data_line[1])+int(palabrasdelafrase)
          data_line[2] = int(data_line[2])+int(letrasdelafrase)
          data_line[3] = int(data_line[3])+1
          data_line[4] = user.nameColor
          data_line[5] = user.fontColor
          data_line[6] = user.fontFace
          data_line[7] = user.fontSize
          data_line[8] = message.body
          data_line[9] = room.name
        else: #but if name is found and room doesn't matches. #PROBLEM HERE
          escribiendoestadisticas = open("listas\Estadisticas.txt", 'a')
          escribiendoestadisticas.write(json.dumps([user.name, palabrasdelafrase, letrasdelafrase,
                                                  "1", user.nameColor, user.fontColor, user.fontFace, user.fontSize, message.body, room.name])+"\n")
          escribiendoestadisticas.close()
      data.append(data_line)
      break
    f.seek(0)
    f.writelines(["%s\n" % json.dumps(i) for i in data])
    f.truncate()

它的目的是添加一个 user.name 并更新它的信息,只要该行的属性 9 匹配。如果不匹配,则使用相同的 user.name 但属性 9 的新值将新行添加到列表中。

如果属性 9 匹配,它会完美运行,但如果不匹配,它所做的是覆盖该 user.name 的现有值并开始计算 [1]、[2] 和 [3] 中的属性从头开始。

感谢您的帮助。

编辑:使用答案中的信息进行更新:

else: 
  data = []
  with open('listas\Estadisticas.txt', 'r+') as f:
    lines = f.readlines()
  for line in lines:
    data_line = json.loads(line)
    if data_line[0] == user.name: 
      if data_line[9] == room.name:
        data_line[1] = int(data_line[1])+int(palabrasdelafrase)
        data_line[2] = int(data_line[2])+int(letrasdelafrase)
        data_line[3] = int(data_line[3])+1
        data_line[4] = user.nameColor
        data_line[5] = user.fontColor
        data_line[6] = user.fontFace
        data_line[7] = user.fontSize
        data_line[8] = message.body
        data_line[9] = room.name
      data.append(data_line)
  f.seek(0)
  f.writelines(["%s\n" % json.dumps(i) for i in data])
  f.truncate()
  for line in lines: 
    data_line = json.loads(line)
    if data_line[0] == user.name: 
      if not data_line[9] == room.name:
        escribiendoestadisticas = open("listas\Estadisticas.txt", 'a')
        escribiendoestadisticas.write(json.dumps([user.name, palabrasdelafrase, letrasdelafrase,
                                                "1", user.nameColor, user.fontColor, user.fontFace, user.fontSize, message.body, room.name])+"\n")
        escribiendoestadisticas.close()

但现在我收到错误:ValueError: I/O operation on closed file。 完全迷路了。

【问题讨论】:

  • 您是要即时追加到文件中,还是在最后重写整个文件?你肯定不想两者都做
  • 我不确定最里面的else 条件是否有意义。如果一个用户名可以在文件中多次使用不同的房间号,您可能希望搜索整个文件,直到找到匹配的房间,而不是在找到第一个匹配的名称后中断。
  • 是的,现在注意到了,它应该只用于一个房间,所以整个列表中只有 1 个同名用户。但是现在我正在升级它以允许几个相同的 user.names 只是在 value[9] 中具有不同的房间并且......我迷路了。
  • @abarnert 我想即时追加文件。

标签: python json list


【解决方案1】:

看起来您正在修改文件,同时仍在读取文件。首先完全加载文件,然后让上下文处理程序关闭文件:

else: #Si está, suma datos
  data = []
  with open('listas\Estadisticas.txt', 'r+') as f:
      lines = f.readlines()

  for line in lines:
    data_line = json.loads(line)
    if data_line[0] == user.name: #if name is found...
      if data_line[9] == room.name: #And room also, then update info.
        data_line[1] = int(data_line[1])+int(palabrasdelafrase)
        [etc]

正如其他人在 cmets 中指出的那样,您可能希望在整个文件中搜索 user.name,而不仅仅是逐行搜索。

另外,正如@abarnert 指出的那样,不如在循环中修改data,然后在最后写出完整的信息集。


几个通用的cmets:

  • data_line 包含少于 10 个项目时,您的代码无法处理这种情况。如果发生这种情况,您的程序将会崩溃。

  • 最好使用json 将整个dict 保存到文件中。这样,当您加载dict 时,您可以立即检查并访问user.name。我建议您将user.name 设为字典的键。

它可能看起来像这样(编辑:看到你想要 user.name 和 room.name 的独特组合):

with open('listas\Estadisticas.json', 'rb') as f:
    data = json.load(f)

key = (user.name, room.name)

if key in data:
    data[key]['nameColor'] = user.nameColor
    [...etc...]
else:
    # I am not sure what details are different
    data[key] = {} # New sub-dict
    data[key]['nameColor'] = user.nameColor
    [...etc...]

with open('listas\Estadisticas.json', 'wb') as f:
    json.dump(f, data)
  • 名字可以改变。这就是为什么数据库通常使用不是人名或房间名称的键。我建议您将事物的名称分配给其他抽象的东西,例如数字,然后在需要显示时查找名称。如果一个用户的名字最初输入错误,后来他们想更正他们名字的拼写,你将很难向他们解释你不能,因为这意味着他们的所有数据都将丢失......李>

【讨论】:

  • 虽然我明白你们两个的意思,但恐怕我太菜鸟了,无法在没有json模块的逐行方法的情况下在整个文件中搜索用户名。所以我只是想解决办法。
  • 以前从未使用过字典,但如果我对这段代码的理解是正确的,你说房间名在哪里是列表中的值 9?
  • 所以,我的data不是一个列表。它是一个带键的字典。键是一个包含两个条目的元组:user.nameroom.name。如果尚未为用户分配房间,则元组看起来就像(user.name, "")。以这种方式设置可以轻松找到用户,并防止重复用户和房间的组合。
  • 在我说if key in data的地方,我正在检查是否已经输入了用户和房间的组合。如果该检查失败,则意味着该组合尚未输入(在这种情况下,我猜您想添加它?
  • 是的,我明白了,但是如果 [3] 或 [9],您对 python 程序的值是 room.name 在哪里说?或者我不需要专门设置它,程序将检查 user.name 是否与 [1]、[2]、[3]、[4]、[5]、[6] 中的 room.name 匹配, [7]、[8] 和 [9]?如果是这种情况,我认为它不会起作用,因为我想如果我在 [8] 中的机会值与 [9] 中的 room.name 相同,但在该行中 [9] 不同,我会得到错误的信息.
猜你喜欢
  • 2020-11-27
  • 2020-05-23
  • 2022-11-27
  • 1970-01-01
  • 1970-01-01
  • 2019-08-07
  • 1970-01-01
  • 1970-01-01
  • 2022-06-20
相关资源
最近更新 更多