class, __init__, self — the three keywords ai uses every time
A class is a template
When AI generates code for anything that has attributes that travel
together — User, Order, ChatSession, Embedding, Agent,
PromptTemplate, APIResponse — what it's giving you is a class.
A class is a small template that bundles a chunk of data with the functions that operate on that data. Once you have a class, you can create as many copies as you need (each one with its own data) and call the same functions on every copy.
You will rarely write classes from scratch in your day job, especially
early on. But you will read them in every real Python codebase: ORM
models in Django or SQLAlchemy, API schemas in pydantic, custom
exceptions, agent state in LangChain, and the response objects from
nearly every SDK (openai, anthropic, requests).
If you can't read a class definition, you can't read most of the production Python that AI is going to write you.
The mental model: a class is a cookie cutter
The class definition is the cutter. Each instance is a cookie. The cutter shapes every cookie the same way, but each cookie is a separate piece of data.
class User: # the cutter — the template
def __init__(self, name):
self.name = name
def greet(self):
return f"hi, {self.name}"
u1 = User("maya") # cookie 1 — its own name
u2 = User("marcus") # cookie 2 — its own name
After those two lines run, you have two completely separate User
objects in memory. They share the same template (both have a .name
and a .greet()), but the actual data on each one is independent.
The three pieces to recognize
When you see a class in AI code, scan for these three shapes:
class Name:— declares the template. By convention, class names areCapitalCamelCase(User, notuser).def __init__(self, ...)— the constructor. Runs once automatically every time you writeUser(...). Its job is to set up the per-instance data onself.self.something = ...— assigns an attribute on this specific instance. Anywhere later, you can read it back viainstance.something.
There's a fourth piece — methods, which are functions defined inside
the class — but for now, just notice they all start with self as their
first parameter.
A worked example
The editor on the right has the canonical four-line class:
class User:
def __init__(self, name):
self.name = name
def greet(self):
return f"hi, {self.name}"
u = User("maya")
print(u.greet())
Trace what happens when Python runs this:
class User:registers the template. Nothing else happens yet. No instance has been created.u = User("maya")creates a new, empty instance, then calls__init__(self, "maya")on it. Inside__init__,self.name = namestores"maya"on the new instance. Then Python returns the instance and binds it tou.u.greet()calls thegreetmethod withuasself. Inside the method,self.namereads"maya"off the instance. The method returns"hi, maya". Theprintdisplays it.
Output:
hi, maya
Imagine a second line: u2 = User("marcus"). Now there are two
instances. u.greet() returns "hi, maya". u2.greet() returns
"hi, marcus". Same template, different per-instance data — that's the
whole point of classes.
Where AI specifically gets this wrong
Three patterns to flag in code Cursor writes:
-
Using a class when a dict would do. AI sometimes wraps three fields and no behavior in a class. If there are no methods and the data is just key/value pairs, a
dictor adataclassis usually simpler. Watch for empty classes that exist only to hold data. -
Forgetting
selfon a method. Cursor occasionally writesdef greet():inside a class, then callsinstance.greet()and gets a confusingTypeError: greet() takes 0 positional arguments but 1 was given. The fix isdef greet(self):— the next read explains why. -
Mutating shared state. AI sometimes writes a class attribute (a value defined at class level, outside
__init__) that's a list or dict. Every instance ends up sharing the same one, and changes leak across instances. We cover this trap two chapters from now — for now, just note that real per-instance data lives onself.
Run the editor. User("maya") calls __init__, which stashes the name
on the new instance. u.greet() reads it back.