如何在列表理解中进行分配?

时间:2012-04-24 05:05:56

标签: python list-comprehension

我想在列表推导中使用赋值运算符。我怎么能这样做?

以下代码的语法无效。我的意思是如果匹配lst[0],请将''设置为空字符串pattern

[ lst[0] = '' for pattern in start_pattern if lst[0] == pattern ]

谢谢!

7 个答案:

答案 0 :(得分:22)

您似乎在Python中将list comprehensionlooping constructs混淆。

列表理解产生 - 列表!它不适合现有列表中的单个赋值。 (虽然你可以折磨语法来做到这一点......)

虽然目前还不清楚你要从代码中做什么,但我认为它更类似于循环列表(流控制)与生成列表(列表理解)

像这样循环遍历列表:

for pattern in patterns:
   if lst[0] == pattern: lst[0]=''

这是一种合理的方法,你可以在C,Pascal等中做。但你也可以只测试一个值的列表并改变它:

if lst[0] in patterns: lst[0] = ''

或者,如果你不知道索引:

i=lst.index[pattern]
lst[i]=''

或者,如果您有列表列表并想要更改每个子列表的每个第一个元素:

for i, sublst in enumerate(lst):
    if sublst[i][0] in patterns: sublist[i][0]=''

等等,等等。

如果要对列表的每个元素应用某些内容,则可以查看使用列表推导,映射或Python工具包中的许多其他工具之一。

就个人而言,我通常更倾向于使用列表推导来创建列表:

 l=[[ x for x in range(5) ] for y in range(4)]  #init a list of lists...

哪个更自然:

l=[]
for i in range(4):
   l.append([])
   for j in range(5):
      l[i].append(j)      

但要修改相同的列表列表,哪个更容易理解?

此:

l=[['new value' if j==0 else l[i][j] for j in range(len(l[i]))] for i in range(len(l))]

或者这个:

for i,outter in enumerate(l):
    l[i][0]='new value'               

YMMV

Here是一个很好的教程。

答案 1 :(得分:9)

Python语言对表达式和语句有不同的概念。

即使语法有时会让你认为它是一个表达式(例如a=b=99有效但是是一个特殊的语法案例,并且并不意味着b=99是一个类似它的表达式,所以赋值是一个陈述例如在C)中。

列表推导是表达式,因为它们返回一个值,在某种意义上,它们执行的循环是一个事件,主要点是返回的列表。

语句可以包含表达式,但表达式不能包含语句。

尽管如此,列表项分配在内部转换为方法调用(以允许创建类似列表的对象),方法调用是表达式。因此,您可以技术在表达式中使用列表项分配:

[ lst.__setitem__(0, '') for pattern in start_pattern if lst[0] == pattern ]

然而,这被认为是不好的,因为它损害了可读性,并且读取源代码的容易程度是Python语言中的主要焦点。你应该写一个例如......

for pattern in start_pattern:
    if lst[0] == pattern:
        lst[0] = ''

顺便说一下,感谢in运算符相当于更具可读性

if lst[0] in start_pattern:
    lst[0] = ''

列表推导用于它们的返回值,它们在内部进行循环...如果您想要的是循环,那么只需编写一个循环...谁将阅读代码试图理解它的作用将会欣赏很多(无论谁在几周内包括你自己)。

答案 2 :(得分:5)

简而言之:你没有。列表推导用于生成列表,而不是修改现有列表。如果你想修改一个列表,请使用for循环,因为这就是他们的目的。

编写该代码的Pythonic方法类似于:

for pattern in start_pattern:
    if lst[0] == pattern:
        lst[0] = ''
        #the following assumes that pattern will never be ''
        #if that's possible, you can ignore this bit
        break

然而,如果你真的,真的想在一个内部完成任务,并且不介意每个处理你的代码的Python程序员一直都在讨厌它,你可以使用一些函数:

  • 如果要分配的变量是全局变量,则可以执行

        globals().update(var=value)
    
  • 如果要分配的变量是可变序列或地图(例如列表或字典)

        list.__setitem__(index, value)
    

答案 3 :(得分:3)

Python 3.8将引入Assignment Expressions

它是一个新符号::=允许(除其他事项外)进行理解。

这将带来很多潜在的节省成本计算/内存,如上述链接的PEP(适用于SO的格式)的以下代码片段所示:

  

语法和语义

     

在大多数可以使用任意Python表达式的情况下,   出现命名的表达式。格式为NAME := expr,其中   expr是除无括号外的任何有效Python表达式   元组,而NAME是标识符。

     

这样的命名表达式的值与合并的值相同   表达式,另外还有目标是   分配了该值:

     
      
  1. 处理匹配的正则表达式

    if (match := pattern.search(data)) is not None:
        # Do something with match
    
  2.   
  3. 使用2-arg iter()不能轻易重写的循环

    while chunk := file.read(8192):
        process(chunk)
    
  4.   
  5. 重复使用计算成本高的值

    [y := f(x), y**2, y**3]
    
  6.   
  7. 在理解过滤器子句及其输出之间共享子表达式

    filtered_data = [y for x in data if (y := f(x)) is not None]
    
  8.   

最近发布的alpha版本已经提供了此功能(不建议用于生产系统!)。您可以找到the release schedule for Python 3.8 here

答案 4 :(得分:1)

如上述答案中所述,列表理解功能中无法直接赋值,但有一种可行的方法可以使用 ITestExecutor 方法来实现赋值。

不只是 exec 我们可以在 assignments 方法中传递任何 python 表达式来评估它。

在你的情况下,它可以通过

exec

如果我们有一个对象列表,并且我们想在特定条件下为对象的特定属性赋值,那么它可能是这样的:

  [ exec(f"lst[0] = ''") for pattern in start_pattern if lst[0] == pattern ]

注意:这将改变列表中现有对象的状态,并且不会像正常使用列表理解时返回的那样返回对象列表。

答案 5 :(得分:0)

如果您要提出的问题是:

npm ci

或用于模式列表

[ lst[0] = '' for lst in listOfLists if lst[0] == pattern ]

实际上可以轻松完成

[ lst[0] = '' for lst in listOfLists if lst[0] in patterns ]

或再次提供模式列表

[ [''] + lst[1:] for lst in listOfLists if lst[0] == pattern ]

答案 6 :(得分:0)

也许这并不是您要找的东西,但我认为值得介绍这种情况。

假设您有list个字典,例如:

>>> fruits
[{'name': 'apple', 'quantity': 5}, {'name': 'banana', 'quantity': 4}]

通过普通的列表理解,您可能会找到所需的对象:

>>> [d for d in fruits if d['name'] == 'apple'] 
[{'name': 'apple', 'quantity': 5}]

由于上面的if条件,您的列表只有一个元素。

因此,您可以索引唯一的元素,访问其中一个字典键并分配一个值:

>>> [d for d in fruits if d['name'] == 'apple'][0]['quantity'] += 1

结果在这里:

>>> fruits
[{'name': 'apple', 'quantity': 6}, {'name': 'banana', 'quantity': 4}]