Hi all. I'm struggling to get my task to properly ...
# ask-community
j
Hi all. I'm struggling to get my task to properly return multiple values. I specify 'nout=2' in the decorator but I still get the 'Task is not iterable' TypeError. This is the fairly simple flow:
with Flow(constants['name'], result=result) as flow:
k
Hey @John Jacoby, what is your specific error?
Oh you can’t use mapped tasks with
nout
.
This thread goes over it in detail
j
Aha that would do it. Maybe returning a dictionary would suffice.
j
@Kevin Kho Actually, I'd like to return to this topic for a bit if you have the time. I'm not really sure about what the best way to get around this limitation is. It seems to create strong unwanted coupling between a task (let's say Task A) and the next task that's receiving the outputs of the first task (let's say Task B). Let's say Task A produces three outputs, two of which are required by Task B and one of which is used further downstream. It seems to me that the only way to accomplish this is to return something like a tuple or dictionary from Task A and then pass the whole thing to Task B. This prevents me from using descriptive names for each argument in the flow. It also means that Task B requires knowledge of the organization of the output of Task A. Ideally, information about the structure of inputs and outputs would only be required at the flow level, not within individual tasks. Is there a more elegant way of doing this than returning some kind of collection?
Basically, is there a way around having to change the signature of Task B simply because I want to change Task A to a mapped task?
k
The other alternative is to create an intermediate task to reshape the output of task A. What you do is return a list.
Copy code
@task
def taskA(x):
   return [x, x+1, x+2]
so if you map, you get a
List[List]
Copy code
with Flow(...) as flow:
    taskA.map(1,2,3) # [[1,2,3],[2,3,4],[3,4,5]]
what needs to happen is a reshape to multiple lists to chain the mapping.
Copy code
@task(nout=2)
def reshape(list_x):
   x1 = [x[0] for x in list_x]
   x2 = [x[1] for x in list_x]
   return x1, x2
and then you can do:
Copy code
with Flow(...) as flow:
    a = taskA.map(1,2,3) # [[1,2,3],[2,3,4],[3,4,5]]
    x1, x2 = reshape(a)  # x1 = [1,2,3]; x2 = [2,3,4]
and then you can map:
Copy code
@task
def taskB(x1, x2):
   return x2 - x1

with Flow(...) as flow:
    a = taskA.map(1,2,3) # [[1,2,3],[2,3,4],[3,4,5]]
    x1, x2 = reshape(a)  # x1 = [1,2,3]; x2 = [2,3,4]
    taskB.map(x1, x2)    # [1, 1, 1]
j
Thanks! I think I'll probably go this route.