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.
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()
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().
Create s: The constructor receives 'Sally'. For the new object referenced by s, self.x is set to 0 and self.name is set to 'Sally'.
Create j: The constructor runs again for a new object. This object's x is set to 0 and its name is set to 'Jim'.
Call s.party(): The method uses self to refer to s. It increments s.x from 0 to 1.
Compare 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
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
Treating a constructor parameter as if it automatically became an attribute.
A parameter is used inside the constructor, while self.name is the attribute that stores the value on the object.
Fix:
Copy the parameter into an instance attribute with an assignment such as self.name = nam.Assuming that objects made from the same class share the same attribute values.
Each object maintains its own independent copies of attributes.
Fix:
Track the object named before the dot. s.x and j.x belong to different instances.Thinking that a method call operates on every instance of the class.
The call is made through s, so the method uses self for the object represented by s.
Fix:
Identify 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
- A class can be used as a template for creating multiple distinct objects.
- Constructor parameters beyond self let each object receive unique initial values.
- An assignment such as self.name = nam stores a constructor parameter in the current object's attribute.
- Each object maintains independent copies of its attributes.
- A method call made through one object reads or changes that object's attributes rather than the attributes of every instance.
Key Takeaways
- 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.