12

While converting my program using delayed, I stumbled upon a commonly used programming pattern that doesn't work with delayed. Example:

from dask import delayed
@delayed
def myFunction():
    return 1,2

a, b = myFunction()
a.compute()

Raises: TypeError: Delayed objects of unspecified length are not iterable While the following work around does not. But looks a lot more clumsy

from dask import delayed
@delayed
def myFunction():
    return 1,2

dummy = myFunction()
a, b = dummy[0], dummy[1]
a.compute()

Is this the intended behaviour?

Henk
  • 145
  • 1
  • 6

1 Answers1

15

Use the nout= keyword as described in the delayed docstring

@delayed(nout=2)
def f(...):
    return a, b

x, y = f(1)

Docstring

nout : int, optional
    The number of outputs returned from calling the resulting ``Delayed``
    object. If provided, the ``Delayed`` output of the call can be iterated
    into ``nout`` objects, allowing for unpacking of results. By default
    iteration over ``Delayed`` objects will error. Note, that ``nout=1``
    expects ``obj``, to return a tuple of length 1, and consequently for
    `nout=0``, ``obj`` should return an empty tuple.
MRocklin
  • 55,641
  • 23
  • 163
  • 235
  • 1
    Oh man this confused me for so long. This should be front-and-center on the docs. – CMCDragonkai Mar 07 '19 at 07:13
  • Is there a way to set `nout` after the delayed object is already constructed? – CMCDragonkai Mar 26 '20 at 03:10
  • I have a problem where the delayed object comes out of a reduction and a `to_delayed()` function. There doesn't seem to be a way to set `nout` for the `to_delayed()`. I know that it is a delayed tuple. It seems the only way is to explicitly construct delayed unpacking function like `(fst, snd) = dask.delayed(lambda t: t, nout=2)(delayedtuple)`. – CMCDragonkai Mar 26 '20 at 04:17
  • 1
    You can always index your object directly. `x, y = d[0], d[1]` – MRocklin Mar 27 '20 at 22:59
  • That one is way more succinct! – CMCDragonkai Mar 30 '20 at 02:57