简体   繁体   English

如何在列表理解中做作业?

[英]How can I do assignments in a list comprehension?

I want to use the assignment operator in a list comprehension.我想在列表理解中使用赋值运算符。 How can I do that?我怎样才能做到这一点?

The following code is invalid syntax.以下代码是无效语法。 I mean to set lst[0] to an empty string '' if it matches pattern :我的意思是将lst[0]设置为空字符串''如果它匹配pattern

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

Thanks!谢谢!

Python 3.8 will introduce Assignment Expressions . Python 3.8 将引入赋值表达式

It is a new symbol: := that allows assignment in (among other things) comprehensions.这是一个新符号: :=允许在(除其他外)推导式中赋值。 This new operator is also known as the walrus operator .这个新的算子也被称为海象算子

It will introduce a lot of potential savings wrt computation/memory, as can be seen from the following snippet of the above linked PEP (formatting adapted for SO):它将在计算/内存方面引入很多潜在的节省,从上面链接的 PEP 的以下片段中可以看出(适用于 SO 的格式):

Syntax and semantics语法和语义

In most contexts where arbitrary Python expressions can be used, a named expression can appear.在可以使用任意 Python 表达式的大多数上下文中,可以出现命名表达式。 This is of the form NAME := expr where expr is any valid Python expression other than an unparenthesized tuple, and NAME is an identifier.这是NAME := expr的形式,其中expr是除无括号的元组之外的任何有效 Python 表达式,而NAME是标识符。

The value of such a named expression is the same as the incorporated expression, with the additional side-effect that the target is assigned that value:此类命名表达式的值与合并表达式的值相同,但附加的副作用是为目标分配了该值:

  1. Handle a matched regex处理匹配的正则表达式

    if (match := pattern.search(data)) is not None: # Do something with match
  2. A loop that can't be trivially rewritten using 2-arg iter()无法使用 2-arg iter() 重写的循环

    while chunk := file.read(8192): process(chunk)
  3. Reuse a value that's expensive to compute重用计算成本高的值

    [y := f(x), y**2, y**3]
  4. Share a subexpression between a comprehension filter clause and its output在理解过滤器子句及其输出之间共享子表达式

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

This is already available in the recently releases alpha version (not recommended for production systems!).这在最近发布的 alpha 版本中已经可用(不推荐用于生产系统!)。 You can find the release schedule for Python 3.8 here .您可以在此处找到Python 3.8 的发布时间表

It looks like you are confusing list comprehension with looping constructs in Python.看起来您将列表理解与 Python 中的循环结构混淆了。

A list comprehension produces -- a list!列表理解产生——一个列表! It does not lend itself to a single assignment in an existing list.它不适用于现有列表中的单个分配。 (Although you can torture the syntax to do that...) (虽然你可以折磨语法来做到这一点......)

While it isn't exactly clear what you are trying to do from your code, I think it is more similar to looping over the list (flow control) vs producing a list (list comprehension)虽然不太清楚您要从代码中做什么,但我认为它更类似于循环列表(流控制)与生成列表(列表理解)

Loop over the list like this:像这样循环列表:

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

That is a reasonable way to do this, and is what you would do in C, Pascal, etc. But you can also just test the list for the one value and change it:这是一种合理的方法,也是您在 C、Pascal 等中所做的。但是您也可以只测试列表中的一个值并更改它:

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

Or, if you don't know the index:或者,如果您不知道索引:

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

or, if you have a list of lists and want to change each first element of each sublist:或者,如果您有一个列表列表并且想要更改每个子列表的每个第一个元素:

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

etc, etc, etc.等等等等等等

If you want to apply something to each element of a list, then you can look at using a list comprehension, or map, or one of the many other tools in the Python kit.如果您想对列表的每个元素应用一些东西,那么您可以考虑使用列表推导式、映射或 Python 工具包中的许多其他工具之一。

Personally, I usually tend to use list comprehensions more for list creation:就个人而言,我通常更倾向于使用列表推导式来创建列表:

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

Which is more natural than:哪个更自然:

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

But to modify that same list of lists, which is more understandable?但是要修改相同的列表列表,哪个更容易理解?

This:这:

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

or this:或这个:

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

YMMV青年会

Here is a great tutorial on this.是一个很棒的教程。

The Python language has distinct concepts for expressions and statements. Python 语言对表达式和语句有不同的概念。

Assignment is a statement even if the syntax sometimes tricks you into thinking it's an expression (eg a=b=99 works but is a special syntax case and doesn't mean that the b=99 is an expression like it is for example in C).赋值是一个语句,即使语法有时会让你认为它是一个表达式(例如a=b=99可以工作,但它是一个特殊的语法情况,并不意味着b=99是一个表达式,例如在 C 中)。

List comprehensions are instead expressions because they return a value, in a sense the loop they perform is an incident and the main point is the returned list.列表推导式是表达式,因为它们返回一个值,从某种意义上说,它们执行的循环是一个事件,重点是返回的列表。

A statement can contain expressions but an expression cannot contain statements.语句可以包含表达式,但表达式不能包含语句。

That said however list item assigment to is internally converted to a method call (to allow creation of list-like objects) and method calls are expressions.也就是说,列表项分配在内部转换为方法调用(以允许创建类似列表的对象)并且方法调用是表达式。 Therefore you can technically use list item assignment in an expression:因此,您可以在技术上在表达式中使用列表项分配:

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

This is however considered bad because it harms readability and how easy is to read source code is the main focus in the Python language.然而,这被认为是不好的,因为它损害了可读性,阅读源代码的难易程度是 Python 语言的主要关注点 You should write instead for example...例如,您应该改写...

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

that by the way thanks to the in operator is equivalent to the even more readable顺便说一句,感谢in运算符相当于更具可读性

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

List comprehensions are used for their return value and they make a loop internally... If what you want is the loop then just write a loop... whoever will read the code trying to understand what it does would appreciate that a lot (and whoever includes yourself in a few weeks).列表推导式用于它们的返回值,它们在内部创建一个循环......如果你想要的是循环,那么只需编写一个循环......任何阅读代码试图理解它所做的事情的人都会非常感激(和谁在几周内包括你自己)。

In short: you don't.简而言之:你没有。 List comprehensions are for generating lists, not modifying existing lists.列表推导用于生成列表,而不是修改现有列表。 If you want to modify a list, use a for loop, as that's what they're for.如果要修改列表,请使用 for 循环,因为这就是它们的用途。

The Pythonic way to write that code would be something like:编写该代码的 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

However, if you really, really want to do assignment inside one, and don't mind every Python programmer who ever deals with your code hating it for all eternity, there are a few functions you can use:但是,如果您真的,真的想在一个内部进行赋值,并且不介意处理您的代码的每个 Python 程序员永远讨厌它,那么您可以使用一些函数:

  • If the variable you want to assign to is a global, then you can do如果要分配给的变量是全局变量,则可以执行

     globals().update(var=value)
  • If the variable you want to assign to is a mutable sequence or a map (such as a list or a dict)如果要分配给的变量是可变序列或映射(例如列表或字典)

     list.__setitem__(index, value)

As mentioned in the above answers there is no direct assignment possible in the list comprehension feature, but there is a hackable way to do it using the exec method to achieve the assignment.正如上面的答案中提到的,在列表理解功能中不可能直接分配,但是有一种可行的方法可以使用exec方法来实现分配。

Not just assignments we can pas any python expression in exec method to evaluate it.不仅仅是assignments我们可以在exec方法中传递任何 python 表达式来评估它。

In your case, it could be achieved by在你的情况下,它可以通过

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

If we have a list of objects and we want to assign a value to a specific attribute of the object on a specific condition then it could be like:如果我们有一个对象列表,并且我们想在特定条件下为对象的特定属性分配一个值,那么它可能是这样的:

[ exec("p.age_status=child") for p in persons_obj_list if p.age <= 18 ]

Note: This will change the state of existing objects of a list and will not return the list of objects as it returns in normal use of list comprehention.注意:这将更改列表中现有对象的状态,并且不会像在正常使用列表理解时返回的那样返回对象列表。

If what you ment in the question is:如果你在问题中提到的是:

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

or for a list of patterns或模式列表

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

This can actually be done easily这实际上可以很容易地完成

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

or for a list of patterns again或再次获取模式列表

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

Maybe it isn't exactly what you're looking for, but I believe that it is worth to present this scenario.也许这并不完全是您要寻找的,但我相信呈现这种情况是值得的。

Suppose that you have a list of dictionaries, like this:假设您有一个字典list ,如下所示:

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

With a normal list comprehension, you might find the object that you're looking for:使用正常的列表解析,您可能会找到您要查找的对象:

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

As a result, you have a list with a single element, thanks to the if condition above.因此,由于上面的if条件,您有一个包含单个元素的列表。

Therefore, you can index the only element, accessing one of the dictionary keys and assigning a value:因此,您可以索引唯一的元素,访问字典键之一并分配一个值:

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

Here the result:结果如下:

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

I can suggest you, use a class instead of using variables to assign values.我可以建议您使用类而不是使用变量来分配值。 When you use a class you can simply change the class value and then return the result.当您使用类时,您可以简单地更改类值,然后返回结果。

I added one example that I did:我添加了一个我做过的例子:

def foo():
class result:
    def __init__(self):
        self.key = 0
        self.value = 0
        
    def change(self, key, value):
        self.key= key
        self.value= value
        return key

result_object= result()
class_result= [result_object.change(key, value) for key, value in temp_dict.items() if value > result_object.value][-1]
return class_result

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM