单行循环迭代器与“if”filter?
愚蠢的问题:
我有一个简单的循环,然后是一个简单的if语句:
for airport in airports: if airport.is_important:
我想知道如果我能以某种方式把它写成一行。
所以,是的,我可以这样做:
for airport in (airport for airport in airports if airport.is_important):
但它却是如此愚蠢和多余( for airport in airport for airport in airports...
)。
有没有更好的办法?
不,没有更短的路。 通常,你甚至会把它分成两行:
important_airports = (airport for airport in airports if airport.is_important) for airport in important_airports: # do stuff
这是更灵活,更容易阅读,仍然不消耗太多的内存。
你可以做
for airport in filter(lamdba x: x.is_important, airports): # do stuff...
我会在循环中使用负面防守。 它是可读的,不会引入额外的缩进级别。
for airport in airports: if not airport.is_important: continue <body of loop>
Mabe这个,但它或多或less是相同的详细…
import itertools for airport in itertools.ifilter(lambda x: x.is_important, airports): ...
这是python的devise哲学。 如果你把太多的话放在一条线上,应该分成几行来帮助那些追随你的人。 列表和生成器expression式更多地用于在位转换迭代 – 制作更可读的map
和filter
forms。
以下是其他一些filter版本的替代方法:
from operator import attrgetter as attr for airport in filter(attr('is_important'), airports): ...
这具有相当简洁的优点,并让您使用点符号attr('first_class.is_full')。
你也可以把类似的东西(或一个使用列表理解的版本)放到一个效用函数filter_by_attr中。 那么你可以这样做:
for airport in filter_by_attr(airports, 'is_important'): ...
尽pipe如此,我仍然认为e-satis是正确的把它放在一个新的variables中,不pipe你使用什么方法。 这样做更加清楚,特别是如果使用不完全匹配有问题的属性名称(或者标准更复杂)。
我唯一要注意的是,如果你发现自己在几个地方使用了这个,也许你应该使机场成为一个特殊的集合,'important_airports'是@property,它返回已过滤的集合。 或者其他抽象来隐藏过滤(如服务调用)。
使用列表理解(只有机场是对象列表):
for airport in [a for a in airports if a.is_important]: