Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/apache-flex/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在列表理解中设置局部变量?_Python_List Comprehension - Fatal编程技术网

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

Python 如何在列表理解中设置局部变量?,python,list-comprehension,Python,List Comprehension,我有一个获取列表并返回对象的方法: # input a list, returns an object def map_to_obj(lst): a_list = f(lst) return a_list[0] if a_list else None 我想得到一个包含所有映射元素的列表,这些元素不是None 像这样: v_list = [v1, v2, v3, v4] [map_to_obj(v) for v in v_list if map_to_obj(v)] 但是在列

我有一个获取列表并返回对象的方法:

# input a list, returns an object
def map_to_obj(lst):
    a_list = f(lst)
    return a_list[0] if a_list else None
我想得到一个包含所有映射元素的列表,这些元素不是
None

像这样:

v_list = [v1, v2, v3, v4]

[map_to_obj(v) for v in v_list if map_to_obj(v)]
但是在列表理解中调用两次
map\u to\u obj
方法似乎不太好

是否有一种方法可以在列表理解中使用局部变量,从而使其具有更好的性能

或者编译器会自动优化它吗

以下是我想要的:

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

您可以使用python内置程序避免重新计算:


使用嵌套列表理解:

[x代表x在[map_to_obj(v)代表v在v_列表中]如果x]

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


[x代表x in(映射到v对象(v)代表v in v_列表),如果x]

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

other_list = []
for v in v_list:
    obj = map_to_obj(v)
    if obj:
        other_list.append(obj)
现在,如果您确实想要一个列表comp,而不想构建一个tmp列表,那么您可以使用迭代器版本的
filter
map

import itertools as it
result = list(it.ifilter(None, it.imap(map_to_obj, v_list)))
或者更简单地说:

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

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

我找到了一种使用
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, [])

这方面的性能如何?

可以通过欺骗一点并使用额外的“for”来设置局部变量,该“for”通过包含局部变量所需值的1元素元组进行“迭代”。以下是使用此方法解决OP问题的方法:

[o for v in v_list for o in (map_to_obj(v),) if o]
这里,
o
是为每个
v
设置的等于
map_to_obj(v)
的局部变量


在我的测试中,这比Liing Dog的嵌套生成器表达式稍微快一点(也比OP对
map\u to_obj(v)
的双重调用快一点),如果
map\u to_obj
函数不太慢的话,它会比嵌套生成器表达式快一点。

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

[x   for v in l   for x in [v]]
这是一个更一般的答案,也更接近你的建议。 因此,对于您的问题,您可以写:

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

从Python 3.8开始,引入(
:=
运算符),可以在列表理解中使用局部变量,以避免调用两次相同的函数:

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

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

有一个迭代解决方案吗?@HaoTan不在python 3中;在Python3中,
map
返回一个map对象,而不是列表,
filter
返回一个filter对象;因此,这将在不制作中间列表的情况下链接函数。是否可以使用
reduce
来完成此工作?@HaoTan:为什么
reduce
用于将多个内容组合成一个内容,而不是将多个内容更改为多个内容。成对的
map
filter
(即
list
ified)所做的工作相当于同时执行过滤和映射操作的listcomp所做的工作。这是一个很好的答案,当然与的答案相同,列表理解取代了
map
filter
。。。我会投票,因为我喜欢用l-c翻译的
过滤器
,但OP可能会批准其中任何一个答案,因为这两个答案都是好的、有用的答案。内在理解应该是一个生成器表达式。不需要建立整个列表,然后扔掉空的项目来构建另一个列表。@提姆的建议听起来很有意义,请考虑编辑你的答案来反映他的建议。@考伯特:如果是<代码> lambda < /Cord>(实际上,任何Python实现的函数都可以内联,以避免调用开销)是的,listcomp赢了。
map
/
filter
如果回调函数是C内置的,则可以赢,因为它们可以将所有工作推送到C层,绕过listcomp无法避免的字节码解释器开销,因为它们是Python级别的函数,只需直接支持附加到列表步骤的字节码。Sil举个例子:将behzad的答案改为用
None替换
lambda t:t不是None
。\uu_____
,尽管它的工作方式有点奇怪(对于其他
None
s,它返回
False
,而对于其他所有的
则返回
NotImplemented
,这恰好是真实的),将提高该解决方案的速度(在本地测试中,
过滤器
工作下降近2倍)您可以使用
timeit
模块为不同的解决方案计时,但您上面的代码片段是一种任意的过于复杂的方式,可以完成一件非常简单的事情-我怀疑它会比普通的for循环或filter/imap解决方案更快或更节省空间…@Bruno我喜欢y我们的“过度复杂化”!如果我看一下没有itertools的答案,我敢说性能是最能表达意图的,因此也是最具可读性的。那么性能呢?我不知道您在
f(lst)上花费了多少cpu
调用,但以这种或那种方式删除
None
s不太可能改变整个画面。
reduce
在这里真的不被调用。它的用途是将值列表减少为单个值(通常是将标量列表减少为单个标量),而不是将一个列表转换为另一个列表。这与我的回答不同,只是使用了一个单元素列表而不是一个单元素元组,我认为元组在列表不需要可变时优于列表。:-)
[o for v in [v1, v2, v3, v4] if (o := map_to_obj(v))]