Concepts / Instance Variables and Class Design

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.

  • Programming
Interactive lab

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

  1. Dog(...) makes a new, empty instance and calls Dog.__init__(new_object, ...); self.name = ... stores into that object's __dict__.
  2. Reading obj.attr looks in obj.__dict__ first, then in the class.
  3. Assigning obj.attr = value always writes obj.__dict__, so it shadows a class attribute for that one object only.
  4. Mutating a class-level list (self.tricks.append) changes the one list every instance shares.
  5. 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.

Educational simulation

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
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

Definition

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.

Employee classthe class being definedsupervisor fieldinstance variableEmployee objectanother object of the sameclassdeclaresrefers to
How does an instance variable of type Employee point to another Employee object, and how does that self-referencing field form a 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.

python
Output (expected)
Ana
Notes on the code
  • 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.

engineerstarting objectmanagerreached via supervisorbosssupervisor field is emptysupervisorsupervisor
Starting from the engineer, which reference do I follow next, where does the chain end, and at which step does the actual result differ from the expected one?

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.

Worked example

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?

  1. 1
    Read 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.

  2. 2
    Read 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.

  3. 3
    Read boss.name

    The name stored in the boss object is Ana. The chain has reached the end, so the printed result is Ana.

Result

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 like

    A class Employee with a name field of type String and a salary field of type number.

    Why it fails

    String is a different class from Employee, so neither field makes Employee recursive.

    Do this instead

    Check 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 like

    Expecting engineer.supervisor to produce a fresh copy of the manager's name and title.

    Why it fails

    The supervisor field holds a reference to an object that already exists. It does not copy the data into the engineer.

    Do this instead

    Read 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 like

    Assuming that following engineer, then manager, then boss makes three new Employee objects.

    Why it fails

    Following a chain moves from one existing object to the next. No new objects are created during the walk.

    Do this instead

    Treat 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 like

    Reading boss.supervisor and expecting another employee object.

    Why it fails

    The 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 instead

    Stop 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.

bossno supervisormanagersupervised by bossengineersupervised by managermanagesmanages
Which employee reports to which manager, and how do the manager links nest from the boss down to individual employees?

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

MEDIUM

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.