Adding Behavior: Methods
Learning Objectives
- You can define a method on a class and call it on an instance.
- You can explain the role of
selfin a method. - You can write a
__str__method to give an object a readable display. - You can recognise when behaviour belongs on the class rather than in a free-standing function.
In the previous chapter, we created classes that hold data with named fields. But the classes cannot yet do anything — asking whether a session is long, or formatting one for display, would still be a separate function sitting apart from the data. This chapter adds methods: functions that live on the class and operate on an instance.
A Method Is a Function on the Class
Recall the Session from the previous chapter:
class Session: def __init__(self, subject, minutes, date): self.subject = subject self.minutes = minutes self.date = date__init__ is already a method — it is a function defined inside the class. A method you write yourself looks the same. Suppose you often want to know whether a session counts as “long” (sixty minutes or more). As a free-standing function that would be:
def is_long(session): return session.minutes >= 60As a method, it moves inside the class and takes self as its first parameter:
class Session: def __init__(self, subject, minutes, date): self.subject = subject self.minutes = minutes self.date = date
def is_long(self): return self.minutes >= 60self is the same self as in __init__: it is the particular session the method is working on. Inside is_long, self.minutes is that session’s minutes. The method asks whether they reach sixty and returns the answer.
You call a method with dot notation, the same way you read an attribute, but with parentheses because it is a call:
session = Session("math", 90, "2024-03-10")print(session.is_long()) # TrueNotice you do not pass self. When you write session.is_long(), Python automatically supplies session as self. That is the whole trick of method calls: session.is_long() is really “call is_long with self set to session.” The object before the dot becomes self inside the method.
Right Instance with self
The point of self is that the same method works on any instance, and each call operates on the right one:
short = Session("history", 30, "2024-03-11")long = Session("physics", 90, "2024-03-10")
print(short.is_long()) # False -- self is `short`, self.minutes is 30print(long.is_long()) # True -- self is `long`, self.minutes is 90One method definition, two objects, two answers. self is how the method knows which session it was asked about. This is the difference between a method and a free-standing function: the method is attached to the data, and self is its handle on the specific instance it was called on.
The instance before the dot
0 / 5 points
Two sessions use the same is_long method:
short = Session("history", 30, "2026-04-01")long = Session("physics", 90, "2026-04-02")When Python evaluates long.is_long(), what does self refer to inside the method?
A Display Method: __str__
By default, printing an object is unhelpful:
session = Session("math", 45, "2024-03-10")print(session)# <__main__.Session object at 0x7f3a2c1d4e50>That tells you the type and a memory address, neither of which you care about. Python lets you fix this with another specially named method, __str__, which returns a string meant for people to read. Like __init__, the double-underscore name is one Python looks for automatically — you define it, and Python calls it when the object is converted to a string:
class Session: def __init__(self, subject, minutes, date): self.subject = subject self.minutes = minutes self.date = date
def is_long(self): return self.minutes >= 60
def __str__(self): return f"{self.subject.title()}: {self.minutes} minutes on {self.date}"Now the object shows itself usefully:
session = Session("math", 45, "2024-03-10")print(session)# Math: 45 minutes on 2024-03-10This method is still just a method: it takes self, reads the object’s attributes, and returns a string. What makes it special is the name. When you write str(session) or print(session), Python looks for __str__ and uses the string it returns. A good __str__ pays for itself the first time you print an object and see useful information instead of a memory address.
Add a __str__ method
0 / 5 points
The starter file contains a Plant class with name, height_cm, and location.
Add a method named __str__(self).
The method must return a string in this exact format:
NAME in LOCATION (HEIGHT cm)The plant name and location must be title-cased — use .title(). For example:
str(Plant("basil", 18, "kitchen"))returns:
Basil in Kitchen (18 cm)When print(plant) is used, Python should show the same text.
Requirements:
- keep the constructor working,
- read the object’s attributes with
self, - do not print anything,
- and do not use
input(...).
When Behaviour Belongs on the Class
Not every function that touches a session should become a method. The useful test is whether the behaviour is fundamentally about one session, using mostly that session’s own data.
The methods is_long and __str__ pass the test: each concerns a single session and reads only that session’s fields. They belong on Session.
A function like totals_by_subject, on the other hand, is about a collection of sessions, not any single one. It does not belong on Session — there is no one session it is “about”. That sort of a function should operate on a collection class.
Method or helper
0 / 5 points
Which behavior most clearly belongs as a method on one Ticket object?
Methods and Collection Classes
Let’s revisit the StudyLog class from the previous chapter, which holds a list of sessions:
class StudyLog: def __init__(self, sessions): self.sessions = sessionsThis is a class that holds a collection of records, and it is the natural home for methods that operate on the whole collection. For example, totals_by_subject belongs on StudyLog — it is about the whole log, not any one session — and it would be rewritten as:
class StudyLog: def __init__(self, sessions): self.sessions = sessions
def totals_by_subject(self): totals = {}
for session in self.sessions: subject = session.subject minutes = session.minutes
totals[subject] = totals.get(subject, 0) + minutes
return totalsNow, a programmer using the StudyLog and Session classes can create a log, add sessions to it, and ask the log to summarise itself — all with methods that live on the relevant classes and operate on their data. The behaviour is organised around the data it operates on, and the programmer does not have to know about separate functions or how they work.
log = StudyLog([ Session("math", 45, "2024-03-10"), Session("physics", 90, "2024-03-10"), Session("history", 30, "2024-03-11"), Session("math", 60, "2024-03-11"), Session("math", 25, "2024-03-12"),])
print(log.totals_by_subject())# {'math': 130, 'physics': 90, 'history': 30}Instances as Function Arguments
The previous examples have focused on methods, but you can also pass instances to free-standing functions. For example, the format_session function from the previous chapter would be rewritten as:
def format_session(session): return f"{session.subject}: {session.minutes} min on {session.date}"Similarly, a function that would check whether a session is “long” would be:
def is_long(session): return session.minutes >= 60And a function that would be given a list of sessions and return the total minutes for a subject would be:
def total_minutes_for_subject(sessions, subject): total = 0 for session in sessions: if session.subject == subject: total += session.minutes
return totalThe decision on whether something should be a method that lives on the class or a free-standing function that takes instances as arguments is a design choice. The test is whether the behaviour is fundamentally about one instance, using mostly that instance’s own data. If so, it belongs on the class as a method; if not, it belongs on a collection class or as a free-standing function.
Check Your Understanding
- What does the first parameter of a method,
self, refer to? - When you call
session.is_long(), where does theselfinsideis_longcome from? - What is
__str__for, and when does Python call it? - The chapter gives a test for whether a piece of behaviour belongs on a class. What is that test?
- Why does a function like
totals_by_subjectnot belong on theSessionclass?
AI Study Aid
Create a chapter diagram
We're looking into to what extent AI-generated diagrams could help with studying.
Use this study aid to generate an AI-generated visual summary of the material you just studied.
Each diagram style emphasizes the content in a different way, so you can choose the focus
that feels most useful.
Using the diagram generator is voluntary and does not affect your course progress. We encourage
you to try it out and see if it helps, but it's totally up to you! Your answers help us understand
how to make better study aids in the future.