pandas AttributeError: can't set attribute (itertuples, shape)
AttributeError: can't set attribute in pandas almost always means you assigned to an itertuples() row (an immutable namedtuple) or to a read-only DataFrame property like df.shape or df.values. On Python 3.11+ the property case reads property 'shape' of 'DataFrame' object has no setter. Write with df.at[row.Index, col] instead.
1. The two causes: itertuples rows and DataFrame properties
import pandas as pd
df = pd.DataFrame({"name": ["a", "b"], "qty": [1, 2]})
for row in df.itertuples():
try:
row.qty = 10
except AttributeError as e:
print("itertuples row:", e)
break
for attempt, f in [("df.shape", lambda: setattr(df, "shape", (2, 2))),
("df.values", lambda: setattr(df, "values", [[0, 0]])),
("df.dtypes", lambda: setattr(df, "dtypes", "int64")),
("df.T", lambda: setattr(df, "T", df))]:
try:
f()
print(attempt, "ok")
except AttributeError as e:
print(attempt + ":", e)
pandas 2.3.3 on Python 3.10.22:
/w/b1.py:9: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access
for attempt, f in [("df.shape", lambda: setattr(df, "shape", (2, 2))),
/w/b1.py:10: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access
("df.values", lambda: setattr(df, "values", [[0, 0]])),
/w/b1.py:12: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access
("df.T", lambda: setattr(df, "T", df))]:
itertuples row: can't set attribute
df.shape: can't set attribute 'shape'
df.values: can't set attribute 'values'
df.dtypes: can't set attribute 'dtypes'
df.T: can't set attribute 'T'
pandas 3.1.0 on Python 3.14.7:
/w/b1.py:9: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/docs/dev/user_guide/indexing.html#attribute-access
for attempt, f in [("df.shape", lambda: setattr(df, "shape", (2, 2))),
/w/b1.py:10: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/docs/dev/user_guide/indexing.html#attribute-access
("df.values", lambda: setattr(df, "values", [[0, 0]])),
/w/b1.py:12: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/docs/dev/user_guide/indexing.html#attribute-access
("df.T", lambda: setattr(df, "T", df))]:
itertuples row: can't set attribute
df.shape: property 'shape' of 'DataFrame' object has no setter
df.values: property 'values' of 'DataFrame' object has no setter
df.dtypes: property 'dtypes' of 'DataFrame' object has no setter
df.T: property 'T' of 'DataFrame' object has no setter
Rows from itertuples() are namedtuples, which are immutable, so row.qty = 10 raises AttributeError: can't set attribute on both Python versions. Assigning to a read-only DataFrame property (shape, values, dtypes, T) raises the same error on Python 3.10, but Python 3.11+ rewords it as property 'shape' of 'DataFrame' object has no setter, so search results for one message may not mention the other. For three of the four, pandas also printed a UserWarning: Pandas doesn't allow columns to be created via a new attribute name just before the error.
2. Fix: write through the DataFrame with .at, or skip the loop
import pandas as pd
df = pd.DataFrame({"name": ["a", "b"], "qty": [1, 2]})
# change a cell while looping: use the index with .at
for row in df.itertuples():
df.at[row.Index, "qty"] = row.qty * 10
print(df)
# better: no loop at all
df["qty"] = df["qty"] + 1
print(df["qty"].tolist())
Output, identical on both setups:
name qty
0 a 10
1 b 20
[11, 21]
row.Index is the row label, so df.at[row.Index, "qty"] = ... changes the real frame. Assigning to the row object could never have worked even if it were mutable: it is a copy. Usually the loop isn't needed at all; a vectorised column expression does the same in one line. To change dtypes use astype; to change the shape, select or reindex.
3. Related trap: df.newcol = ... does not create a column
import warnings
import pandas as pd
warnings.simplefilter("always")
df = pd.DataFrame({"qty": [1, 2]})
df.total = df["qty"] * 2
print(df.columns.tolist(), type(df.total).__name__)
df["total"] = df["qty"] * 2
print(df.columns.tolist())
pandas 2.3.3 on Python 3.10.22:
/w/b3.py:5: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access
df.total = df["qty"] * 2
['qty'] Series
['qty', 'total']
pandas 3.1.0 on Python 3.14.7:
/w/b3.py:5: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/docs/dev/user_guide/indexing.html#attribute-access
df.total = df["qty"] * 2
['qty'] Series
['qty', 'total']
Assigning to an attribute name that isn't a column or property doesn't raise: it sets a plain Python attribute, warns, and the column list stays ['qty']. Always create columns with df["total"] = .... The plain-Python version of this error, for your own classes, is covered in AttributeError: can't set attribute / property has no setter.
Related: pandas 3 breaking changes · SettingWithCopyWarning · apply errors='coerce'.
Frequently asked questions
How do I modify a row while iterating with itertuples?
You can't modify the row object; it's an immutable copy. Use df.at[row.Index, 'col'] = value, or better, replace the loop with a vectorised column expression.
Why does the error say 'has no setter' instead of 'can't set attribute'?
Python 3.11 changed the message for read-only properties. In our test Python 3.10 said "can't set attribute 'shape'" and Python 3.14 said "property 'shape' of 'DataFrame' object has no setter". The namedtuple message stayed "can't set attribute".
Why doesn't df.total = ... create a column?
pandas sets a plain Python attribute and emits a UserWarning; the column is not added. Use df['total'] = ... instead.
Written with AI assistance. Measured on 2026-10-23 in Docker: pandas 2.3.3 on python:3.10-alpine (Python 3.10.22) and pandas 3.1.0 on python:3-alpine (Python 3.14.7). Outputs pasted unedited. PlainTables is our extension; Python and pandas are free.