【问题标题】:Generating dictionary of lists in a loop (3.2.3)在循环中生成列表字典 (3.2.3)
【发布时间】:2015-04-16 08:41:57
【问题描述】:

我需要创建一个字典,其中键是字符串,值是列表。诀窍是我需要循环执行。

目前我的最小化代码如下所示:

for elem in xmlTree.iter():

  # skipping root element
  if elem.tag == xmlTree.getroot().tag:
    continue
  # this is supposed to be my temporary list
  tmpList = []
  for child in elem:
      tableWColumns[elem.tag] = tmpList.append(child.tag)
print(tableWColumns)

这仅打印在上次迭代中创建的列表。

问题显然在于,每当我更改列表时,它的所有引用也会更改。我用谷歌搜索了那个。我没有用谷歌搜索的是使用循环时如何处理它。

当我想保留列表时,我应该使用的解决方案是将其复制到其他列表,然后我可以更改原始列表而不会丢失数据。当我基本上需要动态执行此操作时,我不知道该怎么做。

我也仅限于使用标准库。

【问题讨论】:

  • “问题显然在于,每当我更改列表时,它的所有引用也会更改。”不;如果您多次重复使用同一个列表,这可能是一个问题,但这不是您正在做的事情。 (如果它您的问题,制作列表的新副本而不是重复使用相同的列表的最简单方法是将其切片 - 例如,使用 tmpList[:] 而不是 tmpList。但是,再说一遍,这不是你的问题。)
  • 此外,您的代码并没有按照您所说的那样做——您不会只获得在最后一次迭代中创建的列表,您会为每个值获得None。一个最小的例子很好,但它必须实际证明你正在寻求帮助的问题。有关如何创建好的示例的更多信息,请参阅帮助中的 MCVE

标签: python list dictionary iteration


【解决方案1】:

问题是因为您在每次迭代中创建tmpList = [] 列表并将其放入[]。因此python 在每次迭代中将新的替换为旧的,因此您会在列表中看到最后一次迭代结果。

您可以改为使用collections.defaultdict

from collections import defaultdict
d=defaultdict(list)

for elem in xmlTree.iter():
  # skipping root element
  if elem.tag == xmlTree.getroot().tag:
    continue
  # this is supposed to be my temporary list
  for child in elem:
      d[elem.tag].append(child.tag)
print(tableWColumns)

或者你可以使用dict.setdefault方法:

d={}
for elem in xmlTree.iter():
  # skipping root element
  if elem.tag == xmlTree.getroot().tag:
    continue
  # this is supposed to be my temporary list
  for child in elem:
      d.setdefault(elem.tag,[]).append(child.tag)
print(tableWColumns)

还要注意@abarnert 说tmpList.append(child.tag) 将返回None.so 在分配后实际上python 会将None 分配给tableWColumns[elem.tag]

【讨论】:

  • 这只是他问题的一小部分;这意味着每个重复的标签只显示标签的最后一个副本的结果,但实际发生的是每个标签都以None结尾。
  • @abarnert 哎呀!我第一次看到我注意到的问题!然后忘了说!谢谢提醒!我也很高兴你在很长一段时间后回到 SO ;)
【解决方案2】:

这里最大的问题是tmpList.append(child.tag) 返回None。事实上,Python 中几乎所有的变异方法都返回None

要解决这个问题,您可以进行突变,然后在单独的语句中插入值:

for child in elem:
    tmpList.append(child.tag)
tableWColumns[elem.tag] = tmpList

... 或者不首先尝试改变列表。例如

tableWColumns[elem.tag] = tmpList + [child.tag for child in elem]

这将解决您的 all-values-are-None 问题,但是您遇到了一个新问题。如果任何标签出现多次,您只会从该标签的最后一个副本中获取孩子,而不是从所有副本中获取。那是因为您每次都建立一个新列表,并将 tableWColumns[elem.tag] 重新分配给该新列表,而不是修改那里的任何内容。

要解决这个问题,您需要将现有值提取到tmpList,而不是创建一个新值:

tmpList = tableWColumns.get(elem.tag, [])
tableWColumns[elem.tag] = tmpList + [child.tag for child in elem]

或者,正如Kasra's answer 所说,您可以使用defaultdictsetdefault 方法来简化此操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    • 2017-12-04
    • 1970-01-01
    • 2021-07-07
    • 2021-01-23
    • 2020-08-07
    • 2023-01-28
    相关资源
    最近更新 更多