AttributeError: 'DataFrame' object has no attribute 'append'
1 · The lesson
readWhat this error means
Your code calls df.append(...), and that method no longer exists. It was deprecated in pandas 1.4 and removed in pandas 2.0 (April 2023), together with Series.append. The code isn't wrong so much as old — it was written for pandas 1.x, and most tutorials and Stack Overflow answers from before 2023 still use it. The replacement is pd.concat, or, better in most cases, not appending at all.
When you see it
Traceback (most recent call last): File "main.py", line 5, in <module> sales = sales.append({"region": "North", "units": 12}, ignore_index=True) ^^^^^^^^^^^^ File ".../pandas/core/generic.py", line 6318, in __getattr__ return object.__getattribute__(self, name) ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^ AttributeError: 'DataFrame' object has no attribute 'append'. Did you mean: '_append'?
The Series version:
AttributeError: 'Series' object has no attribute 'append'. Did you mean: '_append'?
Do not take that "Did you mean" hint. Python 3.13 is just pointing at the closest-named attribute; _append is a private pandas internal with a leading underscore precisely so you won't depend on it. It can change or vanish in any release.
Why it happens
df.append never added to the DataFrame in place. It copied the whole thing, plus the new row, every single time. Inside a loop that's quadratic: the thousandth row copies 999 rows to add one. The pandas team removed it rather than keep a method that looked like list.append but behaved nothing like it.
import pandas as pd sales = pd.DataFrame({"region": ["South"], "units": [8]}) sales = sales.append({"region": "North", "units": 12}, ignore_index=True) # AttributeError
How to fix it
Building a table row by row? Collect plain dicts in a list, create the DataFrame once. This is the fix for nine out of ten cases, and it's far faster than any form of appending:
import pandas as pd orders = [ ("Ada", "keyboard", 2, 49.99), ("Grace", "monitor", 1, 189.00), ("Linus", "mouse", 3, 19.50), ] rows = [] for customer, item, qty, price in orders: rows.append({"customer": customer, "item": item, "qty": qty, "total": qty * price}) df = pd.DataFrame(rows) print(df)
rows.append there is an ordinary Python list append, which is cheap. The expensive work happens once, at pd.DataFrame(rows).
Joining DataFrames you already have? pd.concat. Pass a list of frames; use ignore_index=True if the old index labels don't mean anything:
import pandas as pd january = pd.DataFrame({"region": ["North", "South"], "units": [120, 95]}) february = pd.DataFrame({"region": ["North", "South"], "units": [134, 88]}) sales = pd.concat([january, february], ignore_index=True) print(sales)
If you're loading many monthly CSVs in a loop, put each DataFrame in a list and call pd.concat once after the loop — not once per file, which has the same quadratic problem as the old append.
Adding exactly one row to an existing frame? Two options. With a default RangeIndex (0, 1, 2…), df.loc[len(df)] = ... writes a new row at the next label:
import pandas as pd sales = pd.DataFrame({"region": ["South"], "units": [8]}) sales.loc[len(sales)] = ["North", 12] print(sales)
This only works safely when the index really is 0 to n-1. After filtering or set_index, len(df) might be a label that already exists, and you'd overwrite that row without a word. In that case use concat with a one-row frame:
import pandas as pd sales = pd.DataFrame({"region": ["South"], "units": [8]}) new_row = pd.DataFrame([{"region": "North", "units": 12}]) sales = pd.concat([sales, new_row], ignore_index=True) print(sales)
Series.append → pd.concat too.
import pandas as pd week_one = pd.Series([310, 295, 340], name="visits") week_two = pd.Series([360, 372], name="visits") visits = pd.concat([week_one, week_two], ignore_index=True) print(visits.tolist()) # [310, 295, 340, 360, 372]
Pinning pandas<2 in requirements.txt to make the old code run is a stopgap, not a fix. You'll lose two years of bug fixes and the next library upgrade will fight you on it.
When you'd actually see this in real code
- A scraper or API loop written in 2021 that does
df = df.append(row, ignore_index=True)for every result. - A Jupyter notebook from an old course that suddenly breaks after a fresh
pip install pandas. - A Colab or Kaggle notebook — both moved to pandas 2.x, and older shared notebooks stopped running.
- A results-collecting loop in a model evaluation script:
results = results.append({"model": name, "score": score}, ...).
Related errors
- ValueError: The truth value of a Series is ambiguous — the other pandas error everyone meets early on.
- AttributeError: 'list' object has no attribute 'X' — when you have a plain list and call a DataFrame method on it.
- AttributeError: module 'X' has no attribute 'Y' — the same kind of break when a library removes a function between versions.
See Also
- All Python errors — the full index, by type and by when it happens.
- Pandas: Working with Tables
- Pandas DataFrames: Command Center
- Data Cleaning & Wrangling
Found this useful? Share it with a friend who’s learning Python.