Question
I have a pandas DataFrame named df:
import pandas as pd
df = pd.DataFrame({
'c1': [10, 11, 12],
'c2': [100, 110, 120]
})
It looks like this:
c1 c2
0 10 100
1 11 110
2 12 120
How can I iterate over the rows of this DataFrame?
For each row, I want to access its cell values by column name, like this:
for row in df.rows:
print(row['c1'], row['c2'])
I found similar examples suggesting these approaches:
for date, row in df.T.iteritems():
pass
and
for row in df.iterrows():
pass
However, I do not understand what the row object actually is in these examples, or how to use it correctly.
Short Answer
By the end of this page, you will understand how row iteration works in a Pandas DataFrame, what iterrows() returns, how to access values by column name, and when to prefer alternatives like itertuples() or vectorized Pandas operations.
Concept
In Pandas, a DataFrame is a table-like data structure with rows and columns. Each column has a name, and each row has an index.
When you iterate over a DataFrame row by row, Pandas does not give you a plain dictionary automatically. Instead, the exact object depends on the method you use:
df.iterrows()returns pairs of(index, row)rowis a Pandas Series- You can access values from that Series using column names like
row['c1']
Example:
for index, row in df.iterrows():
print(index, row['c1'], row['c2'])
Why this matters:
- Beginners often expect
rowto be a dictionary - In reality,
rowbehaves more like a labeled one-dimensional array - Knowing this helps you read and write DataFrame code correctly
Also, row iteration is usually not the fastest Pandas approach. Pandas is designed for vectorized operations, which means working with entire columns or the whole DataFrame at once.
For example, instead of looping:
for index, row in df.iterrows():
print(row['c1'] + row['c2'])
You can often do:
df['sum'] = df['c1'] + df['c2']
That is shorter, faster, and more idiomatic in Pandas.
Mental Model
Think of a DataFrame as a spreadsheet.
- The DataFrame is the whole sheet
- A row is one horizontal line in the sheet
- A Series is like taking one row and turning it into a labeled list
So when you use iterrows(), Pandas hands you:
- the row label (
index) - a row object (
Series) where:- the labels are the column names
- the values are the cell values in that row
It is similar to receiving this for the first row:
index = 0
row = pd.Series({'c1': 10, 'c2': 100})
Then you can do:
row['c1']
row['c2']
So the main idea is: a row from iterrows() is a Series with column names as keys.
Syntax and Examples
Basic row iteration with iterrows()
import pandas as pd
df = pd.DataFrame({
'c1': [10, 11, 12],
'c2': [100, 110, 120]
})
for index, row in df.iterrows():
print(index, row['c1'], row['c2'])
Output:
0 10 100
1 11 110
2 12 120
What is happening?
df.iterrows()produces one row at a time- Each item is a pair:
(index, row) indexis the row label (0,1,2)rowis aSeries
Inspect the row type
for index, row in df.iterrows():
print(type(row))
print(row)
break
Output will be similar to:
<class 'pandas.core.series.Series'>
c1 10
c2 100
Name: 0, dtype: int64
This shows that each row is a Series whose index contains the column names.
Access by column name
for index, row in df.iterrows():
value1 = row['c1']
value2 = row['c2']
print(f"c1={value1}, c2={value2}")
Faster alternative: itertuples()
for row in df.itertuples(index=True):
print(row.Index, row.c1, row.c2)
Output:
0 10 100
1 11 110
2 12 120
itertuples() is often faster than iterrows() and is commonly preferred when you truly need to loop.
Step by Step Execution
Consider this code:
import pandas as pd
df = pd.DataFrame({
'c1': [10, 11],
'c2': [100, 110]
})
for index, row in df.iterrows():
print('index:', index)
print('c1:', row['c1'])
print('c2:', row['c2'])
Step-by-step
-
Pandas creates a DataFrame with two columns:
c1andc2. -
df.iterrows()starts producing rows one at a time. -
On the first loop:
indexis0rowis a Series like:
c1 10 c2 100 Name: 0, dtype: int64 -
row['c1']returns10 -
row['c2']returns100 -
On the second loop:
indexis1row['c1']is11row['c2']is110
Important detail
This means iterrows() does not return only the row. It returns:
(index, row)
So this is wrong:
for row in df.iterrows():
print(row['c1'])
Because row is actually the whole tuple (index, Series).
Correct version:
for index, row in df.iterrows():
print(row['c1'])
Real World Use Cases
Row iteration is useful when you need to process records one at a time, especially when each row triggers some external action.
Common practical examples
-
Sending API requests
- Each row contains user data or product data
- You loop through rows and send one request per record
-
Generating files or messages
- Each row becomes an email, report line, or JSON payload
-
Data validation
- Check each row for missing or invalid combinations of values
-
Database migration scripts
- Read rows from a CSV into a DataFrame, then insert or transform records one by one
-
Logging or auditing
- Compare fields in each row and record issues
Example: building payloads
for _, row in df.iterrows():
payload = {
'amount': row['c1'],
'total': row['c2']
}
print(payload)
But if your goal is calculation or transformation inside Pandas, prefer vectorized code when possible.
Real Codebase Usage
In real projects, developers usually avoid row iteration unless they truly need it.
Common patterns
1. Vectorized transformations first
df['difference'] = df['c2'] - df['c1']
This is preferred over looping.
2. Use iterrows() for readability when row labels matter
for index, row in df.iterrows():
if row['c1'] < 0:
print(f"Invalid row at index {index}")
3. Use itertuples() for performance
for row in df.itertuples(index=False):
print(row.c1, row.c2)
4. Guard clauses during row processing
for _, row in df.iterrows():
if pd.isna(row['c1']):
continue
print(row['c1'])
5. Build Python objects from rows
records = []
for _, row in df.iterrows():
records.append({
'c1': row['c1'],
'c2': row['c2']
})
6. Validation and error handling
for index, row in df.iterrows():
try:
result = row['c2'] / row['c1']
print(result)
except ZeroDivisionError:
print(f"Row {index} has c1 = 0")
These are realistic situations where looping is acceptable because the work per row is more than simple arithmetic.
Common Mistakes
1. Forgetting that iterrows() returns (index, row)
Broken code:
for row in df.iterrows():
print(row['c1'])
Why it fails:
rowis actually a tuple, not a Series
Correct code:
for index, row in df.iterrows():
print(row['c1'])
2. Expecting row to be a dictionary
A row from iterrows() behaves similarly to a mapping because you can use column names, but it is a Series, not a plain dict.
for _, row in df.iterrows():
print(type(row))
3. Modifying row and expecting the DataFrame to change
Broken expectation:
for _, row in df.iterrows():
row['c1'] = 999
This often does not update the original DataFrame as expected.
Better approach:
df.loc[:, 'c1'] = 999
Or if you must update specific rows:
for index, row in df.iterrows():
df.loc[index, 'c1'] = row['c1'] * 2
4. Using row loops for simple column math
Less ideal:
for index, row in df.iterrows():
df.loc[index, 'sum'] = row['c1'] + row['c2']
Better:
df['sum'] = df['c1'] + df['c2']
5. Using df.T.iteritems() without understanding it
df.T transposes the DataFrame, swapping rows and columns. That changes the structure and usually is not the clearest way to iterate rows.
Prefer:
for index, row in df.iterrows():
print(row['c1'])
6. Assuming iterrows() preserves exact dtypes per row
Because rows are returned as Series, data types may be converted in ways beginners do not expect. If dtype fidelity or speed matters, itertuples() is often better.
Comparisons
Row iteration methods in Pandas
| Method | What it returns | Access style | Speed | Best use |
|---|---|---|---|---|
iterrows() | (index, Series) | row['c1'] | Slower | Beginner-friendly row access by column name |
itertuples() | named tuples | row.c1 | Faster | Performance-sensitive loops |
| Vectorized operations | whole columns/arrays | df['c1'] + df['c2'] | Fastest | Most calculations and transformations |
iterrows() vs itertuples()
iterrows()
Pros:
- Easy to understand
- Access by column name with
row['column'] - Good for learning and simple scripts
Cons:
- Slower
- Returns Series objects
- Can change dtypes row by row
itertuples()
Pros:
- Faster
- Cleaner for read-only row access
- Often preferred in production loops
Cons:
- Access is usually attribute-based, like
row.c1 - Slightly less flexible if you strongly want dictionary-like access
Looping vs vectorized code
| Approach | Example | Recommended? |
|---|---|---|
| Row loop | for _, row in df.iterrows(): ... | Only when needed |
| Vectorized | df['sum'] = df['c1'] + df['c2'] | Yes, usually |
If your task is column-based math, filtering, replacing, or transformation, vectorized Pandas code is usually the right choice.
Cheat Sheet
Quick reference
Iterate with iterrows()
for index, row in df.iterrows():
print(index, row['c1'], row['c2'])
- Returns
(index, row) rowis apandas.Series- Access values by column name:
row['column_name']
Ignore the index if you do not need it
for _, row in df.iterrows():
print(row['c1'])
Faster row iteration with itertuples()
for row in df.itertuples(index=False):
print(row.c1, row.c2)
Best for calculations: vectorized code
df['sum'] = df['c1'] + df['c2']
Rules to remember
iterrows()gives you index + rowrowis a Series, not a dict- Do not rely on modifying
rowto update the DataFrame - Prefer
itertuples()for faster loops - Prefer vectorized operations when possible
Common patterns
for index, row in df.iterrows():
if row['c1'] > 10:
print(index)
for row in df.itertuples():
print(row.Index, row.c1)
Edge case
If column names are not valid Python identifiers, itertuples() attribute access can be less convenient. In that case, iterrows() may feel easier.
FAQ
What does df.iterrows() return in Pandas?
It returns an iterator of (index, row) pairs. The row value is a Pandas Series.
How do I access a column value while iterating rows?
With iterrows(), use the column name:
for _, row in df.iterrows():
print(row['c1'])
Is iterrows() the best way to loop through a DataFrame?
Not usually. It is fine for simple row-by-row tasks, but vectorized operations or itertuples() are often better.
What is the difference between iterrows() and itertuples()?
iterrows() returns Series objects and allows row['c1']. itertuples() returns named tuples and is usually faster.
Can I modify the DataFrame by changing row inside iterrows()?
Do not rely on that. Update the DataFrame directly with .loc or use vectorized assignments.
Why do some examples use for _, row in df.iterrows()?
The underscore means the index is being ignored because it is not needed.
Should I use df.T.iteritems() to iterate rows?
Usually no. It transposes the DataFrame first, which is less direct and often less clear than using iterrows() or itertuples().
Mini Project
Description
Build a small script that reads a Pandas DataFrame of products and prints a summary for each row. This demonstrates how to iterate through rows, access values by column name, and decide when a loop is appropriate.
Goal
Create a script that loops through a DataFrame and prints a formatted message for each product using values from named columns.
Requirements
[ "Create a DataFrame with columns named product, price, and quantity", "Iterate through each row using a Pandas row iteration method", "Access each value by its column name or row attribute", "Print a sentence showing the product name and total value for that row" ]
Keep learning
Related questions
@staticmethod vs @classmethod in Python Explained
Learn the difference between @staticmethod and @classmethod in Python with clear examples, use cases, mistakes, and a mini project.
Add Rows to a Pandas DataFrame in Python
Learn how to add rows to a Pandas DataFrame, why repeated row appends are slow, and when to use loc, concat, or record lists.
Call a Function by Name in a Python Module
Learn how to call a function by name in a Python module using strings, getattr, and safe patterns for dynamic function dispatch.