Skip to main content
← Blog
Pattern Guide3 min read

AI Slop in Python: 10 Patterns Coding Agents Leave Behind

The Python patterns coding agents leave most often, the cleaner version of each, and the aislop rule that flags it.

Ten patterns coding agents often leave in Python, each with a cleaner version and the aislop rule that flags it. They run and usually pass tests, so they get through review. For the language-neutral list, see 20 AI slop code examples.

Hidden errors and shared state

1. The broad except that returns a default

def load_settings(path):
  try:
      with open(path) as f:
          return json.load(f)
  except Exception:
      return {}

A missing file, a permissions error and malformed JSON all become “no settings”. Catch the exception you expect and let the rest raise:

def load_settings(path):
  try:
      with open(path) as f:
          return json.load(f)
  except FileNotFoundError:
      return DEFAULT_SETTINGS

Rules: ai-slop/python-broad-except, and ai-slop/python-bare-except for the even broader except:. See swallowed exception.

2. The mutable default argument

def add_tag(tag, tags=[]):
  tags.append(tag)
  return tags

The list is created once and shared by every call that omits tags, so state leaks between calls. Default to None instead:

def add_tag(tag, tags=None):
  tags = [] if tags is None else tags
  tags.append(tag)
  return tags

Rule: ai-slop/python-mutable-default.

Verbose shapes from SlopCodeBench

The SlopCodeBench paper found agent-written Python more verbose than human-maintained code. These four rules target the most repeatable causes.

3. range(len()) loops

# slop
for i in range(len(users)):
  names.append(users[i].name)

# clean
names = [user.name for user in users]

Iterate directly, or use enumerate when you need the index. Rule: ai-slop/python-range-len-loop.

4. Chained dict.get with empty defaults

# slop
city = payload.get("user", {}).get("address", {}).get("city", "")

# clean: validate once at the boundary
user = User.model_validate(payload)
city = user.address.city

Each {} fallback hides missing data. Validate once at the boundary with a typed model (Pydantic, a dataclass, a TypedDict) so real gaps fail loudly. Rule: ai-slop/python-chained-dict-get.

5. The if/elif dispatch ladder

# slop
if event == "created":
  handle_created(data)
elif event == "updated":
  handle_updated(data)
elif event == "deleted":
  handle_deleted(data)
elif event == "archived":
  handle_archived(data)

# clean
HANDLERS = {
  "created": handle_created,
  "updated": handle_updated,
  "deleted": handle_deleted,
  "archived": handle_archived,
}
HANDLERS[event](data)

The chain grows by one branch per requirement. A dispatch table, or match on Python 3.10+, makes the next case one line. Rule: ai-slop/python-repetitive-dispatch, which flags four or more branches on the same value.

6. The isinstance ladder

if isinstance(value, int):
  return str(value)
elif isinstance(value, float):
  return f"{value:.2f}"
elif isinstance(value, Decimal):
  return format(value, "f")
elif isinstance(value, str):
  return value

The same chain, on types. Normalize the input once, or use a handler map or functools.singledispatch. Rule: ai-slop/python-isinstance-ladder.

Leftovers and undeclared dependencies

7. Debug print() calls

print("DEBUG response:", response.json())

A leftover from the agent checking its work, and a leak once the response holds a token. Use logging or delete it. Rule: ai-slop/python-print-debug.

8. Imports the project does not declare

import requests          # not in pyproject.toml
from dateutil import parser  # installed globally on one laptop

It works on the agent’s machine and fails in CI. A package that does not exist at all invites slopsquatting. aislop checks imports against the standard library, pyproject.toml, requirements files and uv workspaces. Rule: ai-slop/hallucinated-import.

9. Docstrings and comments that narrate

def get_user(user_id):
  # Get the user from the database using the user id
  # and return the user object
  return db.users.get(user_id)

The comment repeats the code. Keep comments for why. See narrative comment.

10. Unused imports and dead helpers

import os, re, sys      # only os is used

def parse_config_v2(path):
  return parse_config(path)

Imports from code that was rewritten, and a wrapper that only adds a name. Delete both. See unused import and thin wrapper.

Scan a Python project

uvx aislop scan          # or: pipx install aislop && aislop scan
aislop scan --changes    # only what changed
aislop fix               # safe, mechanical fixes

The PyPI package launches the same CLI as npm, so it needs Node.js on PATH (other runners). Besides these rules, aislop runs ruff, a complexity check, and pip-audit plus security pattern checks, and detects Django, Flask and FastAPI. Missing tools are skipped; aislop doctor shows what is installed. See supported languages.

To catch these patterns as the agent writes them, give it rules and a hook: Claude Code, Cursor, Codex. For TypeScript, see AI slop in React and TypeScript.

Frequently asked questions

What does AI slop look like in Python?

Broad except blocks that return a default, mutable default arguments, range(len()) loops, chained .get(..., {}) lookups, long if/elif and isinstance chains, leftover print() calls, undeclared imports and comments that narrate the code.

Doesn't ruff already catch this?

Ruff catches a lot, and aislop runs it for Python formatting and lint. The AI slop rules cover valid, lint-clean code that ruff leaves alone, such as silent fallbacks, dispatch ladders, chained defaults and imports missing from the manifest.

How do I scan Python code for AI slop?

Run uvx aislop scan, or pipx install aislop, from the project root. The PyPI package launches the same CLI as npm, so it needs Node.js on PATH.

Where did aislop's Python rules come from?

From real repositories and from research. The range(len()), chained dict.get, repetitive dispatch and isinstance ladder rules come from the verbosity findings in the SlopCodeBench paper (arXiv 2603.24755), which studied agents writing Python.

Is all agent-written Python slop?

No. These patterns are worth flagging because they pass tests and look reasonable, so they get through review unless something names them.

All posts