pandas-dev/pandas · error · TypeError
Expression objects are not iterable
Error message
Expression objects are not iterable
What it means
Raised by Expression.__iter__ (pandas/core/col.py:360). An Expression is a deferred, unevaluated reference to a column; it has no elements to iterate over until it is evaluated against a concrete DataFrame. Iteration (`for x in expr`, `list(expr)`, `*expr`) is therefore unsupported.
Source
Thrown at pandas/core/col.py:360
condition = condition._eval_expression(df)
if isinstance(replacement, Expression):
replacement = replacement._eval_expression(df)
evaluated.append((condition, replacement))
return ser.case_when(evaluated)
# Keep repr compact; caselist may be large.
repr_str = f"{self!r}.case_when(...)"
return Expression(func, repr_str)
def __repr__(self) -> str:
return self._repr_str or "Expr(...)"
# Unsupported ops
def __bool__(self) -> NoReturn:
raise TypeError("boolean value of an expression is ambiguous")
def __iter__(self) -> NoReturn:
raise TypeError("Expression objects are not iterable")
def __copy__(self) -> NoReturn:
raise TypeError("Expression objects are not copiable")
def __deepcopy__(self, memo: dict[int, Any] | None) -> NoReturn:
raise TypeError("Expression objects are not copiable")
@set_module("pandas")
def col(col_name: Hashable) -> Expression:
"""
Generate deferred object representing a column of a DataFrame.
Any place which accepts ``lambda df: df[col_name]``, such as
:meth:`DataFrame.assign` or :meth:`DataFrame.loc`, can also accept
``pd.col(col_name)``.
.. versionadded:: 3.0.0View on GitHub (pinned to 71959b8cb9)
Solutions
- Evaluate against a DataFrame first and iterate the resulting Series: `for v in df['x']:`.
- If you need the underlying values, call the expression's bound form or use `df['x'].tolist()`.
- Restrict pd.col usage to assign/loc/query/pipe which evaluate the deferred callable.
Example fix
# before
expr = pd.col('name')
for name in expr:
...
# after
for name in df['name']:
... Defensive patterns
Strategy: type-guard
Validate before calling
from pandas.core.col import Expression
def to_iterable(obj, df):
if isinstance(obj, Expression):
return obj._eval_expression(df)
return obj Type guard
from pandas.core.col import Expression
def is_expression(obj) -> bool:
return isinstance(obj, Expression) Try / catch
try:
values = list(expr)
except TypeError as e:
if 'not iterable' in str(e):
values = df[expr._eval_expression(df).name].tolist()
else:
raise Prevention
- Evaluate pd.col expressions against a DataFrame before iterating.
- Keep Expressions confined to assign/loc/query/pipe call sites.
- Iterate df[col] directly when you need values.
When it happens
Trigger: `for v in pd.col('x'):`, `list(pd.col('x'))`, `[*pd.col('x')]`, or unpacking `a, b = pd.col('x')`. Passing an Expression to a function that iterates its argument (sum, map, list, tuple, set).
Common situations: Assuming `pd.col('x')` returns the column's values directly. Mixing deferred Expression objects into generic collection-handling helpers that iterate inputs.
Related errors
- boolean value of an expression is ambiguous
- Expression objects are not copiable
- Expected Hashable, got: {type(col_name)}
- Column '{col_name}' not found in given DataFrame. Hint: did
- '{type(self).__name__}' object is not iterable
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/40671dcd981af9cd.
Report an issue: GitHub.