Instance Variables and Class Design
A class definition is recursive when an instance variable inside it can refer to another object of the same class type.
Try it: Classes, Instances and Attributes
How a class creates instances with __init__ and self, why an attribute read checks the instance's __dict__ before the class, why assigning through an instance never changes the class, how a class-level list is shared by every instance, and why obj.method(x) is Class.method(obj, x).
How it works
- Dog(...) makes a new, empty instance and calls Dog.__init__(new_object, ...); self.name = ... stores into that object's __dict__.
- Reading obj.attr looks in obj.__dict__ first, then in the class.
- Assigning obj.attr = value always writes obj.__dict__, so it shadows a class attribute for that one object only.
- Mutating a class-level list (self.tricks.append) changes the one list every instance shares.
- obj.method is found on the class and bound to obj, so obj.method(x) runs Class.method(obj, x).
Default run (30 steps): Ready: class Dog and the statements you picked. Watch where each attribute is found and where each assignment writes. … Finished. Printed: ['sit'] / Wolf / Canis familiaris / Fido is 5.
Simplified: The lab's own small Python interpreter runs a fixed, hand-written script (you choose the variant and the values, never the code); nothing is executed as real Python. Every script was run in CPython 3.12 with the same inputs and the lab reproduces its output and error messages. Object numbers are illustrative, not real id() values.
Loading the simulation…
A Question About Linked Objects
Imagine several objects that each hold a reference to another object of the same kind. One object points to a second, the second points to a third, and so on. This article starts from that picture rather than from a definition. Keep one question in mind as you read: when one object holds a reference to another object of the same kind, and that object holds a reference to a third, what does the full chain look like, and which object does a given reference actually lead to?
What do you think happens?
An engineer's supervisor field refers to a manager. The manager's supervisor field refers to a boss. Before reading on, which object does the engineer's supervisor field lead to, and then which object does the manager's supervisor field lead to?
Reveal answer
The engineer's supervisor field leads to the manager. Following the chain one step further, the manager's supervisor field leads to the boss, the one employee whose supervisor field has nothing to refer to.
Each supervisor field holds a reference to an object that already exists. Following the chain means moving from one existing object to the next, so the walk ends at the boss.
What Makes a Definition Recursive
A class definition is recursive when an instance variable inside it can refer to another object of the same class type.
The key phrase is the declared type of the field. The recursion comes from the type relationship between a class and its own field. The field's declared type must be the class being defined. A field whose type is Employee, placed inside the class Employee, makes the definition recursive. The field is what creates the self-reference, not any method that runs later.
Recursion is therefore a property of the class design, not of a particular method call. When you look at a class and ask whether it is recursive, check its instance variables. Ask whether any of them is declared to hold an object of that same class.
Mapping a Company Onto an Employee Class
Recursive class definitions arise naturally in many cases. A common motivating case is a class designed to represent the employees at a company. Suppose every employee except the boss has a supervisor, and that supervisor is also an employee. The Employee class would then naturally need an instance variable of type Employee that points to the employee's supervisor. The data model is recursive because the relationship between employees is the same kind of relationship at every level. The class definition mirrors that structure.
The diagram above shows the structure in words: the Employee class declares a supervisor field, and that field's declared type is Employee, so it refers to another Employee object. The self-reference is what forms the structure. Every employee object that has a supervisor holds a reference to one more employee object of the same kind.
Ana- The supervisor parameter is stored in an instance variable, so each object holds its own supervisor reference.
- The boss has no supervisor, so its supervisor value is None, which is the exception described in the company example.
- engineer.supervisor leads to the manager object, and manager.supervisor leads to the boss object.
Tracing the Chain Step by Step
Now trace the chain from the engineer. Start at the engineer object. Read its supervisor field, which leads to the manager object. Then read the manager object's supervisor field, which leads to the boss object. Read the boss object's supervisor field and you find nothing to refer to, which is why the boss is singled out as the one exception. The chain stops there.
The diagram above is read from left to right along the supervisor references. Notice what the walk does not do. It does not copy the manager's data into the engineer, and it does not create new employees along the way. Each supervisor field simply holds a reference to an object that already exists. Following the chain is a matter of moving from one existing object to the next.
Tracing engineer.supervisor.supervisor
Given the three objects from the code sketch, what does engineer.supervisor.supervisor lead to, and what do you get when you read its name?
- 1Read engineer.supervisor
The engineer's supervisor field holds the manager object. The walk has now moved from the engineer to the manager, and no new object was created.
- 2Read manager.supervisor
The second .supervisor reads the manager's supervisor field, which holds the boss object. The walk has moved one more existing object along the chain.
- 3Read boss.name
The name stored in the boss object is Ana. The chain has reached the end, so the printed result is Ana.
The chain leads to the boss object, and the printed name is Ana.
Where a Traced Result Diverges
When a traced chain produces a result you did not expect, the fault is usually at one specific step. Compare your predicted state with the actual one after each reference you follow, and you will locate the step where they split. The most common divergences come from the misunderstandings below.
Common mistake Treating any field as proof that a class is recursive
What it looks likeA class Employee with a name field of type String and a salary field of type number.
Why it failsString is a different class from Employee, so neither field makes Employee recursive.
Do this insteadCheck whether the field's declared type is the class being defined. Only a field of type Employee inside Employee creates the recursion.
Common mistake Believing that following a supervisor reference copies the supervisor's data
What it looks likeExpecting engineer.supervisor to produce a fresh copy of the manager's name and title.
Why it failsThe supervisor field holds a reference to an object that already exists. It does not copy the data into the engineer.
Do this insteadRead the reference as a pointer to the same manager object. Changes made through that object are seen through any reference to it.
Common mistake Expecting the chain to create new employees along the way
What it looks likeAssuming that following engineer, then manager, then boss makes three new Employee objects.
Why it failsFollowing a chain moves from one existing object to the next. No new objects are created during the walk.
Do this insteadTreat each step as a move to an object that was already built when the chain was linked.
Common mistake Looking for a supervisor beyond the boss
What it looks likeReading boss.supervisor and expecting another employee object.
Why it failsThe boss is the one employee whose supervisor field has nothing to refer to, which is why the company example singles it out as the exception.
Do this insteadStop the chain at the boss. An empty supervisor field is the expected end of the chain, not an error in the design.
Common mistake Following the wrong field name when the chain has several reference fields, so the walk lands on an unexpected object
Company Hierarchy as a Tree
The company example is a natural case of a recursive structure. Each employee's supervisor is another employee, and the manager links nest from the top of the company down to the individual employees. Viewed from above, the reporting relationships form a tree. The boss sits at the top, and each lower employee is connected to the supervisor that the supervisor field names.
In the stored data, the arrows run the other way. Each engineer, manager, or other lower employee holds a supervisor reference pointing upward to the next employee in the chain. The tree is simply the same chain read from the top down. The source's diagram shows three employees, but the same pattern holds for a chain of any length.
Your Turn to Trace a Chain
Using the three objects from the code sketch (boss Ana, manager Ben, engineer Cy), predict what the expression engineer.supervisor.name evaluates to, and then say what happens if you extend the chain by writing engineer.supervisor.supervisor.supervisor. Name the object each step reaches, and say where the chain stops.
Hints
- Read one supervisor field at a time, and name the object each field leads to before you read the next one.
- The field engineer.supervisor leads to the manager object, so the name it holds is Ben.
- After the boss, the next supervisor field is empty, so the expression would fail at that step. Ask yourself what the boss's supervisor value is.
Key Takeaways
- A class definition is recursive when an instance variable inside it can refer to another object of the same class type. The declared type of the field is what matters.
- A field of type String inside a class called Employee does not make the class recursive, because String is a different class.
- In a company hierarchy, each employee's supervisor is another employee, so the Employee class naturally needs an instance variable of type Employee. The boss is the exception, with nothing to refer to.
- Following a recursive chain means moving from one existing object to the next through reference fields. It does not copy data or create new objects.
- When a traced result differs from your prediction, compare the expected and actual state after each reference you follow to find the exact step where they split.