为什么 __bool__ 内置函数必须在 dask.delayed 对象上引发异常?

Why does __bool__ built-in function have to raise exception on dask.delayed objects?

我正在尝试 运行 使用 dask API 的任务的 DAG 用于我的特定应用程序。举一个人为的例子,我希望任务传递它们的 success/failure 标志并将它们用作其他任务的输入。

但是,dask 不允许我对延迟对象进行 __bool__ 调用 (a and b)。但它与按位布尔运算有何不同(即 a & b)。

为什么实现为不支持?在本地修复它有多难?

我尝试深入研究源代码,但我无法理解 a & b 如何成功 return 是 ('and_', 'a', 'b'), 但 a and b 不 return 像 ('__bool__1', 'a'), ('__bool__2', 'b' ), ('and_', '__bool__1', '__bool__2').

我提供了最简单的源代码,可以重现问题。

import dask
from time import sleep

@dask.delayed
def task(x, cond):
    if not cond:
        return False
    sleep(x)
    return True

def run_graph():
    task1_done = task(2, True)
    task2_done = task(1, True)
    task3_done = task(1, task2_done)

    all_done = task1_done and task3_done
    return all_done

if __name__ == '__main__':
    done = run_graph()
    dask.compute(done)

如果我们用 & 替换 and 操作,它工作正常。

all_done = task1_done & task3_done

这在这里可能不是问题,但我想使用 all()any() 内置函数来获取延迟标志列表并在内部调用 __bool__

我个人并不详细了解 Dask,但我怀疑它只是在其对象上实现 __and__。这根本不会将对象转换为布尔值。这与 and 或 etc 不同,它们首先将对象转换为布尔值。

这可以通过小测试快速测试class:

In [1]: class Test: 
    ...:     def __and__(self, other): 
    ...:         print("And called!") 
    ...:         return self 
    ...:     def __bool__(self): 
    ...:         print("Bool called!") 
    ...:         return True 
    ...:                                                                                                                                                                                                                             

In [2]: a = Test()                                                                                                                                                                                                                  

In [3]: b = Test()                                                                                                                                                                                                                  

In [4]: a & b                                                                                                                                                                                                                       
And called!
Out[4]: <__main__.Test at 0x7f5eb58f4eb8>

In [15]: a and  b                                                                                                                                                                                                                    
Bool called!
Out[5]: <__main__.Test at 0x7f5eb587e400>

根据我的理解,由于 Dask 确实进行了延迟求值,因此 __bool__ 可能会强制立即求值工作良好,而 __and__ 可以 return 一个惰性对象(因为它returns 是同一类型的对象,不是布尔值。