是否有可能加入其中,与列表理解条款?(Is it possible to add a where c

2019-07-30 13:43发布

请看下面的列表理解

[ (x,f(x)) for x in iterable if f(x) ]

这个过滤根据一个条件可迭代f并返回对x,f(x) 这种方法的问题是f(x)计算两次。 这将是巨大的,如果我们可以写象

[ (x,fx) for x in iterable if fx where fx = f(x) ]
or
[ (x,fx) for x in iterable if fx with f(x) as fx ]

但是在Python我们使用嵌套的内涵,以避免重复调用F(X)来写,这让修真看不太清楚

[ (x,fx) for x,fx in ( (y,f(y) for y in iterable ) if fx ]

是否有任何其他的方式,使之更加符合Python和可读性?


更新

即将在Python 3.8! PEP

# 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]

Answer 1:

你追求已经let语句来语义Python列表内涵,其范围可到两个___ for..in (地图)以及if ___的理解(过滤器)的一部分,其范围依赖于..for ___ in...


您的解决方案,修改后:您(你承认无法读取)溶液[ (x,fx) for x,fx in ( (y,f(y) for y in iterable ) if fx ]是编写优化的最直接的方法。

主要思想:电梯x转换成元组(X,F(X))。

有人会说最“Python化”的方式做事情会是原来的[(x,f(x)) for x in iterable if f(x)]和接受的低效率。

但是,您可以分解出((y,fy) for y in iterable)到一个函数,如果你打算这样做了很多。 这是不好的,因为如果你想有机会获得超过变量x,fx (例如x,fx,ffx ),那么你就需要重写所有列表内涵。 因此,这不是一个很好的解决方案,除非你确信你只需要x,fx和计划重新使用这种模式。


发生器表达式:

主要思想:使用更复杂的替代生成器表达式:一个在那里Python将让你写多行。

你可以只用一台发电机的表达,这与蟒蛇玩很好:

def xfx(iterable):
    for x in iterable:
        fx = f(x)
        if fx:
            yield (x,fx)

xfx(exampleIterable)

这是我会亲自去做。


记忆化/缓存:

主要思想:您也可以使用(滥用?)的副作用,使f有一个全球性的memoization缓存,这样你就不会重复操作。

这可能有一点开销,并且需要的缓存应该多大政策,当它应该是垃圾收集。 因此,这应该只使用,如果你有其他的用途memoizing f或如果f是非常昂贵的。 但是,如果让你写...

[ (x,f(x)) for x in iterable if f(x) ]

......就像你本来想而不做昂贵的操作的性能影响f两次,即使你在技术上称之为两次。 您可以添加@memoized装饰以f : 例如 (不含最大缓存大小)。 这将工作,只要x是可哈希(例如一个数字,一个元组,一个frozenset等)。


虚值:

主要思想:在一个闭包捕获FX = F(x)和修改列表理解的行为。

filterTrue(
    (lambda fx=f(x): (x,fx) if fx else None)() for x in iterable
)

其中filterTrue(迭代)是过滤器(无,可迭代)。 你将不得不修改这个,如果你的列表类型(2元组)实际上能够被None



Answer 2:

有没有where声明,但您可以使用“模拟”它for

a=[0]
def f(x):
    a[0] += 1
    return 2*x

print [ (x, y) for x in range(5) for y in [f(x)] if y != 2 ]
print "The function was executed %s times" % a[0]

执行:

$ python 2.py 
[(0, 0), (2, 4), (3, 6), (4, 8)]
The function was executed 5 times

正如可以看到,功能被执行5次,而不是10或9。

for建设:

for y in [f(x)]

模仿where子句。



Answer 3:

没有说你必须使用内涵。 事实上多数风格指南我见过的要求,你限制他们简单的结构,无论如何。

你可以使用一个生成器表达式,来代替。

def fun(iterable):
    for x in iterable:
        y = f(x)
        if y:
            yield x, y


print list(fun(iterable))


Answer 4:

地图和邮编?

fnRes = map(f, iterable)
[(x,fx) for x,fx in zip(iterable, fnRes) if fx)]


文章来源: Is it possible to add a where clause with list comprehension?