请看下面的列表理解
[ (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]
你追求已经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
。
有没有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子句。
没有说你必须使用内涵。 事实上多数风格指南我见过的要求,你限制他们简单的结构,无论如何。
你可以使用一个生成器表达式,来代替。
def fun(iterable):
for x in iterable:
y = f(x)
if y:
yield x, y
print list(fun(iterable))
地图和邮编?
fnRes = map(f, iterable)
[(x,fx) for x,fx in zip(iterable, fnRes) if fx)]