Designing Classes for Real-World Problems
A class is a template that defines what data and code each object will have; the class keyword does not create an object.
A Template Is Not an Object
When you design a class, you describe the data and code that objects of that class will have. The class is a template, not an object. Writing the class keyword defines that template, but it does not by itself create an object. An object is created when the class is called as if it were a function.
A useful analogy is a cookie cutter. The cutter describes the shape shared by the cookies, but the cutter is not itself a cookie. In the same way, a class describes the structure and behavior that its objects will have, while each object is an individual instance created from that template.
Creating an Initialized Object
Calling a class creates a new object. During that creation, Python automatically runs the object's __init__ method. The purpose of __init__ is to set up the object's initial attributes, giving the object its starting data. In the PartyAnimal example, creating an object sets its x attribute to 0.
class PartyAnimal:
def __init__(self):
self.x = 0
def party(self):
self.x = self.x + 1
print(self.x)
an = PartyAnimal()- 1The class definition describes the data and behavior that PartyAnimal objects will have.
- 2When an =
PartyAnimal()runs, Python creates an object and automatically calls__init__on it. - 3The assignment
self.x= 0 gives that object its initial x value. - 4The party method uses
self.xto read and then increase the same object's value.
- The class defines a PartyAnimal template.
- The
__init__method sets the new object's x attribute to 0. - The party method changes the object's x attribute.
- Calling PartyAnimal creates the object named an.
Following self Through a Method Call
The self parameter refers to the specific object on which a method was called. It lets the method access and modify that object's attributes. In the expression an.party(), self refers to an. Therefore, self.x means the x attribute belonging to an, rather than an attribute belonging to some other object.
What do you think happens?
After an = PartyAnimal(), what will an.x be after three calls to an.party()?
Reveal answer
3
The object starts with x equal to 0. Each call to party uses self to increase that object's x by 1, so three calls produce x equal to 3.
0
1
2
3Designing Shared Behavior
Designing a class means deciding what data belongs to each object and what actions should operate on that data. The class holds the shared design for those attributes and methods. Each object created from the class has its own independent attribute data, while the methods provide reusable behavior for working with that data.
Put behavior that operates on an object's own data into methods, and use self when those methods need to read or modify that data. This keeps one class definition reusable for as many objects as the problem requires.
Independent Object State
One class can produce many objects with the same structure but independent attribute data. If two objects are created from PartyAnimal, each begins with its own x value initialized by __init__. When a method uses self to change one object's x, it operates on the object connected to that method call.
After the call, an.x is 1 and another.x remains 0.Mistakes Beginners Make
Common mistake Treating the class definition as an object
What it looks likeDefining PartyAnimal and assuming an object already exists
Why it failsThe class keyword defines a template. It does not create an object.
Do this insteadCall the class, as in an = PartyAnimal(), to create an object.
Common mistake Ignoring the role of __init__
What it looks likeExpecting an object's initial x value without initialization
Why it fails__init__runs automatically when the object is created and sets up its initial attributes.Do this insteadUse __init__ to establish the object's starting data.
Common mistake Using an object's data without self
What it looks likeWriting a method that changes x instead of using self.x
Why it failsself identifies the particular object whose attribute the method should access or modify.
Do this insteadUse self.x when the method needs the object's x attribute.
Common mistake Assuming one object's method changes every object's data
What it looks likeCalling an.party() and expecting another.x to increaseWhy it failsself is bound to the object on which the method was called.
Do this insteadTrack the object before the dot in the method call; an.party() operates on an.
Practice the Trace
Consider a PartyAnimal object that starts with x equal to 0. Trace the value of x after each of these calls: an.party(), an.party(), an.party(). Then explain which object self refers to during each call.
Hints
- The object is initialized with x equal to 0.
- Each party method call increases the selected object's x by 1.
- In
an.party(), self refers to an.
Tracing Three Method Calls
Determine the value of an.x after an = PartyAnimal() followed by three calls to an.party().
- 1Create the object
Calling PartyAnimal creates an object and automatically runs
__init__, which setsan.xto 0. - 2First call
In
an.party(), self refers to an. The method increasesan.xfrom 0 to 1. - 3Second call
self still refers to an, so the method increases
an.xfrom 1 to 2. - 4Third call
The same method changes the same object's attribute from 2 to 3.
After three calls, an.x is 3.
Key Takeaways
- A class is a template that defines the data and code its objects will have; it is not itself an object.
- Calling a class creates an object, and
__init__runs automatically to initialize that object's attributes. - The self parameter refers to the specific object on which a method was called.
- Methods use self to read and modify the correct object's attributes.
- One class can create many objects with the same structure and independent data.