是否有一种方法可以在单个列表推导中同时进行转换和过滤,即:
def transform(el):
if some_condition(el):
return None
return complex_logic(el)
def main():
transformed = [transform(el) for el in some_list if transform(el) != None]
但避免调用transform
两次?也就是说,把它赋值给一个变量,就像(在伪python中):
def main():
transformed = [transformed for el in some_list let transformed = transform(el) if transformed != None]
从Python 3.8开始可以使用海象操作符:=
:
def main():
return [res for el in some_list if (res := transform(el)) is not None]
这样,调用transform
函数的结果存储在res
中,然后您可以在列表推导的表达式部分使用它。
将let transformed = transform(el)
替换为for transformed in [transform(el)]
我将从简单、习惯到可读的角度来解决这个问题:
使用temp变量的简单循环
简单但冗长的for循环可用于"cache"转换产生一个临时变量t
:
def transform(el):
if some_condition(el):
return None
return complex_logic(el)
def main():
transformed_list = []
for el in some_list:
t = transform(el) # invoked once
if t is not None: # equivalent to `if transform(el) != None`
transformed_list.append(t)
嵌入式列表推导
就像Kelly Bundy建议的那样,嵌入列表推导式:
- 元素转换
- 非空 过滤器
参见列表推导式中的临时变量
变换的解耦条件
可以应用命令查询分离(CQS)
对程序有简化作用,使其状态(通过查询)和状态更改(通过命令)更易于理解。
假设两个给定的函数(some_condition
和complex_logic
)是单独定义的,因为每个函数都实现了单一职责(SRP)。那么利用这种分离并在合适的组合中重用这两个步骤将是重要的:
- 查询:由
filter
首先使用条件函数作为谓词 - 命令:之后通过复杂逻辑转换
这样,管道或流甚至可能变得更可读:
transformed = [complex_logic(el) for el in filter(some_condition, some_list)]
最后,这接近Samwise在他的评论中建议的:现在遵循SRP。