bal*_*lki 22 python list-comprehension python-3.x python-3.8 python-assignment-expression
考虑以下列表理解
[ (x,f(x)) for x in iterable if f(x) ]
Run Code Online (Sandbox Code Playgroud)
这将根据条件过滤可迭代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 ]
Run Code Online (Sandbox Code Playgroud)
但是在python中我们必须使用嵌套的理解来编写,以避免重复调用f(x),这使得理解看起来不那么清晰
[ (x,fx) for x,fx in ( (y,f(y) for y in iterable ) if fx ]
Run Code Online (Sandbox Code Playgroud)
有没有其他方法可以使它更加pythonic和可读?
更新
即将推出的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]
Run Code Online (Sandbox Code Playgroud)
nin*_*cko 10
你试图let在python列表推导中使用-statement语义,其范围可用于理解的___ for..in(map)和if ___(filter)部分,其范围取决于..for ___ in....
您的解决方案,已修改:
您(当您承认不可读)解决方案[ (x,fx) for x,fx in ( (y,f(y) for y in iterable ) if fx ]是编写优化的最直接方式.
主要思想:将x提升到元组(x,f(x)).
有些人认为最"pythonic"的做事方式将是最初的,[(x,f(x)) for x in iterable if f(x)]并接受低效率.
但是((y,fy) for y in iterable),如果你计划做很多事情,你可以把它分解成一个函数.这很糟糕,因为如果您希望访问更多变量而不是x,fx(例如x,fx,ffx),那么您将需要重写所有列表推导.因此,除非您确定只需要x,fx并计划重复使用此模式,否则这不是一个很好的解决方案.
生成器表达:
主要思想:使用更复杂的生成器表达式替代方法:python将允许您编写多行.
你可以使用一个生成器表达式,python可以很好地用于:
def xfx(iterable):
for x in iterable:
fx = f(x)
if fx:
yield (x,fx)
xfx(exampleIterable)
Run Code Online (Sandbox Code Playgroud)
这就是我亲自做的事情.
记忆化/缓存:
主要思想:您还可以使用(滥用?)副作用并制作f全局记忆缓存,这样您就不会重复操作.
这可能会产生一些开销,并且需要一个策略,指出缓存应该有多大以及什么时候应该进行垃圾收集.因此,只有当你有其他用于记忆f的用途,或者如果f非常昂贵时,才应该使用它.但它会让你写...
[ (x,f(x)) for x in iterable if f(x) ]
Run Code Online (Sandbox Code Playgroud)
......就像你最初想要的那样f,即使你在技术上称它两次,也不会在两次做昂贵的操作时受到打击.您可以将@memoized装饰器添加到f:example(没有最大缓存大小).只要x是可清除的(例如,数字,元组,冻结集等),这将起作用.
虚拟价值观:
主要思想:在闭包中捕获fx = f(x)并修改列表推导的行为.
filterTrue(
(lambda fx=f(x): (x,fx) if fx else None)() for x in iterable
)
Run Code Online (Sandbox Code Playgroud)
其中filterTrue(iterable)是filter(None,iterable).如果您的列表类型(2元组)实际上能够存在,则必须修改此项None.
Igo*_*bin 10
没有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]
Run Code Online (Sandbox Code Playgroud)
执行:
$ python 2.py
[(0, 0), (2, 4), (3, 6), (4, 8)]
The function was executed 5 times
Run Code Online (Sandbox Code Playgroud)
如您所见,这些功能执行了5次,而不是10次或9次.
这种for结构:
for y in [f(x)]
Run Code Online (Sandbox Code Playgroud)
模仿where子句.
没有什么说你必须使用理解.事实上,我见过的大多数样式指南要求你将它们限制为简单的结构.
您可以使用生成器表达式.
def fun(iterable):
for x in iterable:
y = f(x)
if y:
yield x, y
print list(fun(iterable))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
16643 次 |
| 最近记录: |