Python 如何在列表理解中设置局部变量?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26672532/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 00:51:22  来源:igfitidea点击:

How to set local variable in list comprehension?

pythonlist-comprehension

提问by Hao Tan

I have a method that takes a list and returns an object:

我有一个接受列表并返回一个对象的方法:

# input a list, returns an object
def map_to_obj(lst):
    a_list = f(lst)
    return a_list[0] if a_list else None

I want to get a list that contains all the mapped elements that aren't None.

我想得到一个列表,其中包含所有不是None.

Like this:

像这样:

v_list = [v1, v2, v3, v4]

[map_to_obj(v) for v in v_list if map_to_obj(v)]

But it doesn't seem good to call the map_to_objmethod twice in the list comprehension.

但是map_to_obj在列表推导中两次调用该方法似乎并不好。

Is there a way to have local variables in list comprehensions so that it can have better performance?

有没有办法在列表推导式中使用局部变量以使其具有更好的性能?

Or does the compiler optimize it automatically?

还是编译器会自动优化它?

Here is what I want:

这是我想要的:

(sml like)
[let mapped = map_to_obj(v) in for v in v_list if mapped end] 

采纳答案by Xavier Guihot

Starting Python 3.8, and the introduction of assignment expressions (PEP 572)(:=operator), it's possible to use a local variable within a list comprehension in order to avoid calling twice the same function:

开始Python 3.8,并引入赋值表达式(PEP 572):=运算符),可以在列表推导式中使用局部变量以避免两次调用相同的函数:

In our case, we can name the evaluation of map_to_obj(v)as a variable owhile using the result of the expression to filter the list; and thus use oas the mapped value:

在我们的例子中,我们可以将 的评估命名map_to_obj(v)为变量,o同时使用表达式的结果来过滤列表;因此o用作映射值:

[o for v in [v1, v2, v3, v4] if (o := map_to_obj(v))]

回答by behzad.nouri

You can avoid re-calculation by using python built-in filter:

您可以使用内置的 python 避免重新计算filter

list(filter(lambda t: t is not None, map(map_to_obj, v_list)))

回答by Lying Dog

Use nested list comprehension:

使用嵌套列表理解:

[x for x in [map_to_obj(v) for v in v_list] if x]

[x for x in [map_to_obj(v) for v in v_list] if x]

or better still, a list comprehension around a generator expression:

或者更好的是,围绕生成器表达式的列表理解:

[x for x in (map_to_obj(v) for v in v_list) if x]

[x for x in (map_to_obj(v) for v in v_list) if x]

回答by bruno desthuilliers

List comprehensions are fine for the simple cases, but sometimes a plain old forloop is the simplest solution:

列表推导式适用于简单情况,但有时简单的旧for循环是最简单的解决方案:

other_list = []
for v in v_list:
    obj = map_to_obj(v)
    if obj:
        other_list.append(obj)

Now if you really want a list comp and dont want to build an tmp list, you can use the iterator versions of filterand map:

现在,如果您真的想要一个列表 comp 并且不想构建一个 tmp 列表,您可以使用filterand的迭代器版本map

import itertools as it
result = list(it.ifilter(None, it.imap(map_to_obj, v_list)))

or more simply :

或更简单地说:

import itertools as it
result = filter(None, it.imap(map_to_obj, v_list)))

The iterator versions don't build a temporary list, they use lazy evaluation.

迭代器版本不构建临时列表,它们使用惰性求值。

回答by Hao Tan

I have figured out a way of using reduce:

我想出了一种使用方法reduce

def map_and_append(lst, v):
    mapped = map_to_obj(v)
    if mapped is not None:
        lst.append(mapped)
    return lst

reduce(map_and_append, v_list, [])

How about the performance of this?

这个性能怎么样?

回答by Ovaflo

A local variable can be set within a comprehension by cheating a bit and using an extra 'for' which "iterates" through a 1-element tuple containing the desired value for the local variable. Here's a solution to the OP's problem using this approach:

局部变量可以通过欺骗一点并使用额外的“for”在包含局部变量所需值的 1 元素元组中“迭代”来在推导中设置。这是使用这种方法解决 OP 问题的方法:

[o for v in v_list for o in (map_to_obj(v),) if o]

Here, ois the local variable being set equal to map_to_obj(v)for each v.

这里,o是局部变量被设置为等于map_to_obj(v)每个v.

In my tests this is slightly faster than Lying Dog's nested generator expression (and also faster than the OP's double-call to map_to_obj(v), which, surprisingly, can be faster than the nested generator expression if the map_to_objfunction isn't too slow).

在我的测试中,这比 Lying Dog 的嵌套生成器表达式略快(也比 OP 对 的双重调用map_to_obj(v)快,令人惊讶的是,如果map_to_obj函数不太慢,它可以比嵌套生成器表达式更快)。

回答by Vincent Goossens

A variable assignment is just a singular binding:

变量赋值只是一个单一的绑定:

[x   for v in l   for x in [v]]

This is a more general answer and also closer to what you proposed. So for your problem you can write:

这是一个更一般的答案,也更接近您的建议。所以对于你的问题,你可以写:

[x   for v in v_list   for x in [map_to_obj(v)]   if x]