问题描述
在Python中发现all()函数后发现此问题并没有像我期望的那样短路,因为您发送的列表内的表达式不是惰性计算的。所以:
all([
previous_task is not None,self.task_type == previous_task.task_type,self.owner is None,previous_task.owner is None,self.is_sibling_of(previous_task)
])
例如,在此代码中,如果previous_task为None,则self.task_type == previous_task.task_type
在尝试访问previous_task.task_type时仍会评估并抛出异常
尽管这样很容易解决(并且实际上短路并且很懒):
previous_task is not None and all([
self.task_type == previous_task.task_type,self.is_sibling_of(previous_task)
])
实际上,核心问题在于列表表达式在创建时会急切地评估内部代码。
因此解决方案是创建一个生成器,因此它实际上仅逐项评估项目。但是...生成器需要对某些东西的理解才能真正生成。或带有yield参数的函数。
尽管我可以做这样的事情:
def __evaluate(self,previous_task):
yield previous_task is not None
yield self.task_type == previous_task.task_type
yield self.owner is None
yield previous_task.owner is None
yield self.is_sibling_of(previous_task)
可读性受到损害,无法达到all
的目的。
我在PEP上发现可以使用类似这样的东西:
(condition
for evaluation
in (
previous_task is not None,self.is_sibling_of(previous_task)
)
)
这也不起作用,因为第二个括号是集合文字,而不是生成器,它将像列表一样评估构造中集合的内容。
另一种选择是从lambda列表中进行reduce参数,如下所示:
reduce(
lambda actual,next_function: actual and next_function(),[
lambda: previous_task is not None
lambda: self.task_type == previous_task.task_type
lambda: self.owner is None
lambda: previous_task.owner is None
lambda: self.is_sibling_of(previous_task)
]
)
太冗长,尽管仍然很可读
那么...我缺少什么吗?有什么方法可以简洁地做到这一点?仅进行懒惰状态评估似乎太困难了
如果只有这些可能性,我可以考虑做一个utils库D:
编辑:忘记了我没有明确提出的显而易见的解决方案,在这里您可以只链接and
,但是事实是这样做违背了all
的目的。而且我认为,从长远来看,知道如何使无关值的生成器有用,而不仅仅是发送and
垃圾邮件,这会妨碍可读性并迫使您以巨大的表达式“硬编码”条件
(previous_task is not None
and self.task_type == previous_task.task_type
and self.owner is None
and previous_task.owner is None
and self.is_sibling_of(previous_task)
)
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)