【问题标题】:Modifying a list with list comprehension使用列表理解修改列表
【发布时间】:2020-04-24 19:24:51
【问题描述】:

我想使用列表推导来修改列表。像这样的:

c = [10,20,30,40,50,60,70,80,90]
a = [0,1,2]
b = [3,4,5]

c[a[jj]] = [c[a[jj]]+c[b[jj]] for jj in range(len(a))]

我的预期输出:

c = [50,70,90,40,50,60,70,80,90]

但是每次出现错误:

    c[a[jj]] = [c[a[jj]]+c[b[jj]] for jj in range(len(a))]
NameError: name 'jj' is not defined

我在这里做错了什么?

编辑: 我试图在不使用 for 循环的情况下复制下面的语句:

for jj in range(len(a)):
    c[a[jj]] = c[a[jj]] + c[b[jj]]

【问题讨论】:

  • 是否只是为了描绘您想要的结果而对列表中的元素进行洗牌?
  • [jj] 变量未在理解括号外定义。理解生成列表,您尝试将其分配给索引为 [jj] 的嵌套列表,但您的主要代码块不知道 [jj] 是什么。
  • 列表推导将返回一个列表。除了没有在列表理解之外定义 JJ 之外,您似乎正在尝试将新列表分配给 c 的特定索引 (a[JJ]),这与您的输出不符。
  • Python 将右侧的表达式完全评估为单个匿名对象,然后将该对象分配给左侧。 jj 早已不复存在。
  • 您想就地修改c 还是使用结果创建一个新列表?修改 c 时,通常首选 for 循环而不是列表推导,因为修改现有列表的唯一方法是使用副作用。

标签: python list list-comprehension


【解决方案1】:

jj 未在左侧定义。即使是这样,作业也不会做你想做的事。你想要一个常规的for 循环:

for jj in range(len(a)):
    c[a[jj]] = c[a[jj]] + c[b[jj]]

但是,您可以使用 enumerate 和 add-assign (+=) 使其更干净:

for jj, x in enumerate(a):
    c[x] += c[b[jj]]

或者更好的是使用zip:

for x, y in zip(a, b):
    c[x] += c[y]

【讨论】:

  • 是的,我知道使用 for 循环,它解决了我的目的。但我希望它使用列表理解的原因是让它更快。因为我有类似的操作在另一个 for 循环中使用 for 循环(在更大的代码中),这最终使代码变慢。因此,我希望如果使用列表推导可以让它更快一点!
  • @stut 我敢打赌,使用 zip 和我提到的 add-assign 运算符比切换到理解式更能提高速度。据我统计,他们每个循环保存 5 个名称查找和 4 个索引。
【解决方案2】:

您正在尝试在未定义的列表理解之外使用循环变量jj。我还没有完全理解列表理解试图做什么,但对于初学者来说,这是你的问题。 jj 仅在该括号区域内定义,而不是在等号的另一侧您分配给 c 的索引。

【讨论】:

    【解决方案3】:

    重复这里多次说过的内容,但添加了一些信息:

    c[a[jj]] = [c[a[jj]]+c[b[jj]] for jj in range(len(a))]

    此列表理解赋值语句引发错误,因为左侧(要分配的目标)尝试获取不存在的项目。您已经编写了索引的索引,这是合法的,但解释器正在搜索一些尚未定义的 jj 引用的索引。

    与字典对象不同,在分配键时可以创建键,当索引在边界内(即要分配的位置已经存在)或已被名称引用时,列表的索引分配会成功执行定义。

    jj 可以在列表理解表达式中使用。列表推导的语法允许在表达式中定义一个新变量作为可迭代 range(len(a)) 的目标。但是因为解释器从左到右评估整个赋值语句,jj 直到列表理解表达式才存在。

    最后,除了语法错误之外,您的代码逻辑不会产生您预期的结果。请编辑您的帖子以准确反映您正在尝试做的事情。

    编辑:下面的 cmets 已经解决了一些需要在此处进行的编辑。

    【讨论】:

    • 你很接近,但有些地方是错误的:1)“尝试获取不存在的项目” - 这是名称jj,不存在,不是项目,即它是 NameError,而不是 IndexError。 2) “解释器从左到右评估整个赋值语句” - RHS 在 LHS 之前被评估。 jj 没有在 LHS 上定义,因为它只绑定在列表理解的范围内。在 Python 2 中,列表推导没有范围,所以没有 NameError,但就像你说的那样,它没有按预期工作。
    • @wjandrea 感谢您的更正。我不知道口译员首先评估 RHS。我一直在阅读解释器以从左到右的顺序阅读,所以我假设这适用于赋值语句:检查名称 then 要分配的值。我可以在哪里阅读更多相关信息?
    • 官方文档中关于Simple statements的一些地方提到过。请注意,增强分配的工作方式不同。这里也有讨论:Is the right-hand side of an assignment always evaluated before the assignment?
    猜你喜欢
    • 2017-06-05
    • 1970-01-01
    • 1970-01-01
    • 2014-06-18
    • 1970-01-01
    • 1970-01-01
    • 2014-02-25
    • 2012-10-11
    • 2023-02-22
    相关资源
    最近更新 更多