""" Example DAG demonstrating the usage of dynamic task mapping with non-TaskFlow operators. """ from __future__ import annotations from datetime import datetime from airflow.sdk import DAG, BaseOperator class AddOneOperator(BaseOperator): """A custom operator that adds one to the input.""" def __init__(self, value, **kwargs): super().__init__(**kwargs) self.value = value def execute(self, context): return self.value + 1 class SumItOperator(BaseOperator): """A custom operator that sums the input.""" template_fields = ('values',) def __init__(self, values, **kwargs): super().__init__(**kwargs) self.values = values def execute(self, context): total = sum(self.values) print(f'Total waas {total}') return total with DAG( dag_id='example_dynamic_task_mapping_with_no_taskflow_operators', start_date=datetime(2022, 3, 4), catchup=False, schedule=None ): add_one_task = AddOneOperator.partial(task_id='add_one').expand(value=[1, 2, 3]) sum_it_task = SumItOperator(task_id='sum_it', values=add_one_task.output)
In the above code, there is 'add_one_task.output'. I'd like to know if every task has the 'output' attribute or only the dynamic mapping task has that attribute.
Short answer:
output is not specific to dynamic task mapping.
In modern Airflow, every operator task has an .output attribute, but it becomes especially important and visible when used with dynamic task mapping.
Let’s unpack this carefully.
What task.output actually is
task.output is an XComArg object.
-
It represents the return value of a task
-
It is a reference, not the actual value
-
Airflow resolves it at runtime
This applies to:
-
TaskFlow tasks (
@task) -
Classic operators (
BaseOperator) -
Mapped tasks
-
Non-mapped tasks
So yes: every task has .output, not just dynamically mapped ones.
Why it exists for classic operators
Historically, only TaskFlow tasks had a clean return-value interface.
Starting in Airflow 2.x, operators gained .output to unify behavior.
For example:
Here, t1.output is a valid XCom reference even though no mapping is involved.
What makes mapped tasks special
Dynamic mapping changes what .output represents, not whether it exists.
Non-mapped task
-
t.output→ a single XCom value -
Example:
2
Mapped task
-
t.output→ a mapped XCom -
Conceptually:
-
Airflow automatically aggregates mapped outputs when passed downstream
This is why sum_it_task can receive values=add_one_task.output as a list.
Why SumItOperator needs template_fields
Because:
-
valuesreceives anXComArg -
Airflow must render it at runtime
-
Templating tells Airflow:
“This field may contain runtime-resolved values.”
This is unrelated to mapping but often seen together.
Summary table
| Scenario | .output exists? | What it represents |
|---|---|---|
| TaskFlow task | ✅ | Return value |
| Classic operator | ✅ | Return value |
| Mapped task | ✅ | List of mapped outputs |
| Non-mapped task | ✅ | Single output |
| Task with no return | ✅ | None |
Key takeaway
-
Every task has
.output -
Dynamic mapping only changes the shape of the output
-
.outputis always anXComArg -
Mapping makes it a collection instead of a single value

浙公网安备 33010602011771号