【问题标题】:Combination of for-loop and index slicing is not returning expected results [duplicate]for循环和索引切片的组合未返回预期结果[重复]
【发布时间】:2018-05-21 13:50:06
【问题描述】:

提前道歉,我不愿意问这样一个新手问题(这是我正在学习的第一门语言),但我的理解显然存在差距,我找不到任何解决问题的内容的链接我正在经历。

下面的代码定义了 3 个字典和一个空列表。然后我运行一个 for 循环,用 30 个“慢速外星人”填充列表。

然后我对列表中的前 10 个条目运行另一个循环,以便将该特定实例更新为“Fast Alien”字典。但是,我似乎要替换列表中的所有字典。

如果有任何帮助将我指向一些进一步讨论/解决/教育我的文章,我们将不胜感激。

slow_alien = {
    "Name": "Slow Alien",
    "Colour": "Green",
    "Points": 10,
    "X Position": 15,
    "Y Position": 20,
    "Current Speed": "Slow",
    "Height": 1.8,
}
medium_alien = {
    "Name": "Medium Alien",
    "Colour": "Yellow",
    "Points": 15,
    "X Position": 30,
    "Y Position": 20,
    "Current Speed": "Medium",
    "Height": 2.2,
}
fast_alien = {
    "Name": "Fast Alien",
    "Colour": "Red",
    "Points": 20,
    "X Position": 45,
    "Y Position": 20,
    "Current Speed": "Fast",
    "Height": 2.6,
}
aliens = []

for alien in range(30):
    aliens.append(slow_alien)

for alien in aliens[:10]:
    if alien == slow_alien:
        alien.update(fast_alien)

for alien in aliens:
    for key, value in alien.items():
        print(str(key) + ": " + str(value))
    print("")
print("The aliens list contains " + str(len(aliens)) + " dictionaries")

谢谢,

卡尔。

【问题讨论】:

  • 另见stackoverflow.com/questions/240178/… 这不是完全相同的问题,但最终结果是相同的:包含对同一对象的多个引用的列表。
  • 如果以下答案之一解决了您的问题,您应该接受它(单击相应答案旁边的复选标记)。这有两件事。它让每个人都知道您的问题已得到您满意的解决,并为帮助您的人提供帮助。有关完整说明,请参阅here
  • 谁说他们需要 30 外星字典?如果他们真的只想要 10 个对单个“常量”fast_alien 的引用和 20 个对单个“常量”slow_alien 的引用怎么办? IMO 的问题是他们误将 dict.update 方法用于替换列表中的条目。替换列表中的项目的正确方法是使用 aliens[i] = fast_alien 重新分配它(并且可能使用 enumerate 来获取索引)。
  • 在这种情况下,问题将与 stackoverflow.com/questions/2582138/… 重复。
  • @PM2Ring,谢谢,已检查答案。

标签: python for-loop indexing slice


【解决方案1】:

该列表有 30 个对同一 slow_alien 字典的引用。

要解决此问题,请尝试以下操作:

aliens = []

for _ in range(30):
    aliens.append(slow_alien.copy())

for alien in aliens[:10]:
    alien.update(fast_alien)

这遵循您当前的方法,但您也可以跳过更新并立即创建快速更新:

aliens = []

for _ in range(10):
    aliens.append(fast_alien.copy())
for _ in range(20):
    aliens.append(slow_alien.copy())

【讨论】:

  • 一般规则:除非您明确要求,否则 Python 从不复制任何内容。可以在这里找到有关 Python 变量真正含义的好读物:nedbatchelder.com/text/names1.html
  • 啊!谢谢!它引用字典而不是复制它的事实是我所缺少的!我会围绕这个主题做一些阅读。再次感谢! :)
  • @bruno - 很好,谢谢。
  • Ned 的那篇文章是所有 Python 程序员的必读文章,恕我直言。很遗憾 Ned 这些天没有在这里发帖。
  • @brunodesthuilliers 这确实是一个很棒的视频;它还向我指出了 open.edx.org 网站,那里有一些很棒的免费课程。再次感谢!
【解决方案2】:

你说:

I then run a for loop to populate the list with 30 "Slow Aliens".

但那是错误的,你实际上用 1 个慢速外星人填充列表 30 次。

如果您确实想要其中的 30 个,则必须在将它们添加到列表时制作一份副本。

for alien in range(30):
    aliens.append(slow_alien.copy())

【讨论】:

    【解决方案3】:

    正如已经指出的那样,创建字典的新副本是正确的答案。我想更明确地说明您的代码实际出了什么问题。

    for alien in range(30):
        aliens.append(slow_alien)
    

    slow_alien 指的是同一个字典,所以你会得到 30 个对那个(同一个)对象的引用。

    for alien in aliens[:10]:
        if alien == slow_alien:
            alien.update(fast_alien)
    

    update() 调用会搞砸一切。循环中的第一个alien 是对slow_alien 字典的引用。所以你真正要做的是slow_alien.update() 并且你有效地改变了对象本身。它将成功进入剩余迭代的条件块,因为每个alienslow_alien 都引用同一个对象,即fast_alien。如果您在代码末尾打印slow_alien == fast_alien,您可以看到这一点。

    如果每个项目都是不同的副本,那么您可以在不触及原始slow_alien 的情况下自行更新该副本。它也可以用列表推导式写得更紧凑。

    aliens = [slow_alien.copy() for _ in range(30)]
    

    【讨论】:

    • 这很有意义。谢谢你。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 2022-07-21
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    相关资源
    最近更新 更多