Understand the idea
A problem you can recognise
Two students have different study goals. A class can describe the shared kind of thing while each instance keeps its own relevant state. If changing one student's goal unexpectedly changes the other, you need to investigate where that state actually lives.
Begin with the small examples before building a hierarchy of classes. You should be able to explain every instance, attribute and method call you create.
Understand the idea
Understand the idea
A class defines a type whose instances can hold related state and behaviour. Use it when the relationship between the data and operations becomes clearer, not merely because classes look more advanced. A small dictionary and a function can be the better design for a simple one-off calculation.
init initialises an instance after it is created. The conventional first parameter self refers to the instance receiving the method call. Assigning self.name creates or updates an attribute on that instance. By contrast, a mutable attribute created directly in the class body can be shared across instances, which is often an unwanted surprise for beginners.
A method call such as session.finish() passes the instance to its method automatically. Keep the method’s state change understandable and protect domain constraints where needed. Public attributes are not automatically validated simply because they belong to a class. The examples focus on separate instance state and a clear method contract; inheritance is not required to organise this small model.
See how it works
Example 1: Create an instance
PYTHON exampleRead the code, then try a change.
Try this example
class Session:
def __init__(self, subject, minutes):
self.subject = subject
self.minutes = minutes
session = Session("Python", 30)
print(session.subject)
print(session.minutes)
Expected output:
ReferenceCompare this with the explanation.
Python
30
The constructor arguments initialise two attributes on the new instance. The class defines the structure; the session name refers to one concrete instance.
See how it works
Example 2: Keep per-instance state separate
PYTHON exampleRead the code, then try a change.
Try this example
class Checklist:
def __init__(self):
self.items = []
first = Checklist()
second = Checklist()
first.items.append("Read")
print(first.items)
print(second.items)
Expected output:
ReferenceCompare this with the explanation.
['Read']
[]
A fresh list is created in each initialisation. Appending to the first instance’s items does not append to the second instance’s separate list.
See how it works
Example 3: Call a state-changing method
PYTHON exampleRead the code, then try a change.
Try this example
class Session:
def __init__(self):
self.completed = False
def finish(self):
self.completed = True
session = Session()
print(session.completed)
session.finish()
print(session.completed)
Expected output:
ReferenceCompare this with the explanation.
False
True
finish receives the instance and changes its completed attribute. The call, not the mere method definition, performs the change.
Understand the idea
Think through the important decisions
The class definition describes behaviour; constructing an instance creates a particular object. Follow the initial values into that object's attributes. self is the parameter through which a method works with the instance supplied by the call, not a magical request to find any object with a similar name.
Create two instances and track their attributes separately. An assignment to one instance's duration should not be confused with changing a shared class-level mutable collection. Keeping a small table for the two objects makes the distinction visible.
Methods are still functions with inputs, effects and return values. A method that prints a message does not necessarily return that message. A method that mutates an attribute should make that effect understandable in its purpose and in the code that calls it. The reasoning habits from the functions lesson still apply.
Check your understanding
Check the reasoning
Instance attributes assigned through self belong to that instance rather than an implicitly shared mutable class collection.
A matching screenshot or output is one check, not proof that a program is correct for all inputs. Change one input, predict the new result and run again. If the result differs, find the first instruction where your prediction stops matching the program state. Keep that small case as a regression check when you fix the cause.
Spot the mistake
The mistake worth understanding
Do not choose a class just because classes sound more advanced. A pure calculation may be clearer as a function, and a simple data record may be enough without a complex hierarchy. Use an object when grouping the state and related behaviour clarifies the problem.
Your turn
Independent practice
Create a StudySession class with subject, minutes and completed instance attributes. Add a finish method. Create two instances, finish only one, and demonstrate that their completion states remain independent.
Your turn
Practice hint
Initialise mutable state inside init . Access the current instance with self.
Change it and explain it
Experiment with the first program Create a StudySession class with subject, minutes and completed instance attributes. Add a finish method. Create two instances, finish only one, and demonstrate that their completion states remain independent. Start by changing one input in this smaller example. Loading it does not execute it.
class Session:
def __init__(self, subject, minutes):
self.subject = subject
self.minutes = minutes
session = Session("Python", 30)
print(session.subject)
print(session.minutes) Open in Practice Loading an example does not run it. Your existing edits are protected by a replacement confirmation.
Your turn
Try a different case
Create two study objects, change one and inspect both. Explain which object each method receives and what the caller gets back. Then describe whether a plain function would express part of the same task more simply.