Accessing Object Attributes and Methods
The real power of object-oriented programming is creating multiple instances of a class, each with its own independent data.
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…
One Class, Many Objects
A class can serve as a template for creating many distinct objects. The important step beyond creating one object is creating several instances that belong to the same class but hold different data. For example, two PartyAnimal objects can begin with different names. They share the class definition, but each object has its own state.
Following Constructor Data
A constructor receives self and any additional parameters supplied by the caller. The self parameter refers to the object instance being created. An additional parameter carries a value chosen for that particular object. Inside the constructor, an assignment such as self.name = nam copies the parameter value into the name attribute of the object represented by self.
The flow is specific to the object being created: the caller supplies a value, the constructor receives it through its parameter, and self.attribute stores it on that object. The assignment does not describe a single shared name for every instance; it stores the value in the current object's attribute.
Constructing Distinct Instances
The first construction passes 'Sally' to the constructor. During that construction, self refers to the new object assigned to s, so that object's x becomes 0 and its name becomes 'Sally'. The second construction creates a completely new object assigned to j. Its x also begins at 0, but its name becomes 'Jim'.
| Object | Initial x attribute | Initial name attribute |
|---|---|---|
| s | 0 | 'Sally' |
| j | 0 | 'Jim' |
The same class creates two objects with different initial name values.
Reading and Changing One Object
An expression such as s.name accesses the name attribute belonging to the object referenced by s. Likewise, j.name accesses the name attribute belonging to the object referenced by j. Because each object maintains independent copies of its attributes, accessing or changing one object's data does not change the other object's corresponding data.
class PartyAnimal:
def __init__(self, nam):
self.x = 0
self.name = nam
def party(self):
self.x = self.x + 1
s = PartyAnimal('Sally')
j = PartyAnimal('Jim')
s.party()- 1
PartyAnimal('Sally')creates the object referenced by s and initializes its x to 0 and name to 'Sally'. - 2
PartyAnimal('Jim')creates a separate object referenced by j and initializes its x to 0 and name to 'Jim'. - 3
s.party()calls the method for the object referenced by s. - 4Inside the method, self refers to s, so
self.xis that object's x attribute. - 5The increment changes
s.xto 1 whilej.xremains 0.
- The constructor gives s its own x and name attributes.
- The second construction gives j its own x and name attributes.
- The call
s.party()operates on the object represented by s. - That object's x changes from 0 to 1; j's x remains 0.
Tracing the Complete Setup
Two Names, Two Object States
Trace the values stored after constructing s = PartyAnimal('Sally') and j = PartyAnimal('Jim'). Then trace the effect of calling s.party().
- 1Create s
The constructor receives 'Sally'. For the new object referenced by s,
self.xis set to 0 andself.nameis set to 'Sally'. - 2Create j
The constructor runs again for a new object. This object's x is set to 0 and its name is set to 'Jim'.
- 3Call s.party()
The method uses self to refer to s. It increments
s.xfrom 0 to 1. - 4Compare the objects
The objects still hold independent data: s has x equal to 1 and name equal to 'Sally'; j has x equal to 0 and name equal to 'Jim'.
Changing the x attribute through s.party() changes s but does not change j.
What do you think happens?
After s = PartyAnimal('Sally'), j = PartyAnimal('Jim'), and s.party(), what are the x values for s and j?
Reveal answer
s.x is 1 and j.x is 0
Each object has its own independent x attribute. The method call through s increments only s's x.
Mistakes with Instance Data
Common mistake Treating a constructor parameter as if it automatically became an attribute.
What it looks likeThe constructor receives nam, but the object has no stored name unless the constructor assigns self.name = nam.
Why it failsA parameter is used inside the constructor, while
self.nameis the attribute that stores the value on the object.Do this insteadCopy the parameter into an instance attribute with an assignment such as self.name = nam.
Common mistake Assuming that objects made from the same class share the same attribute values.
What it looks likeAssuming that changing s.x also changes j.x.
Why it failsEach object maintains its own independent copies of attributes.
Do this insteadTrack the object named before the dot. s.x and j.x belong to different instances.
Common mistake Thinking that a method call operates on every instance of the class.
What it looks likeAssuming s.party() increments both Sally's and Jim's x values.
Why it failsThe call is made through s, so the method uses self for the object represented by s.
Do this insteadIdentify the instance used for the call and follow that instance's attributes.
Practice the Data Flow
Suppose a class constructor receives a parameter called nam and contains self.name = nam. Two objects are created with different name arguments. Explain, in order, how each argument reaches the correct object's name attribute. Then explain why changing an attribute through one object does not change the corresponding attribute in the other object.
Hints
- Start with the value supplied in each constructor call.
- Identify which object self refers to during each constructor execution.
- Separate the attributes belonging to the two object instances.
Key Takeaways
- 1A class can be used as a template for creating multiple distinct objects.
- 2Constructor parameters beyond self let each object receive unique initial values.
- 3An assignment such as
self.name= nam stores a constructor parameter in the current object's attribute. - 4Each object maintains independent copies of its attributes.
- 5A method call made through one object reads or changes that object's attributes rather than the attributes of every instance.
At a glance
- A single class definition can create many objects with different data.
- Constructor arguments flow through parameters and into instance attributes using assignments such as
self.attribute= parameter. - Each object has independent copies of its attributes.
- Accessing or changing one object's attributes does not affect another object's attributes.
- A method call through a particular instance operates on that instance's state.