Practice: Classes and OOP Basics¶
View practice code on GitHub Get the Video Course
From the lesson
Practice problems for Section 13 Concepts. Build each yourself first, then expand the solution to check.
Six practice problems, one per concept step; the numbers line up. Build each yourself, then check python-practice/solutions.
These problems use a music app theme (a Song class with a shared app name, plays, and readable songs), a different domain from the Pyzon Store you build in the concept files, so you apply each idea instead of copying the demo.
Step-01: Why Objects? Your First Class¶
Concepts: a class as a blueprint, a class attribute, creating objects.
Write a program with one class Song:
- Task-1: write the class with a single class attribute
appset toTunefy. - Task-2: create two songs
s1ands2from it, and print each one'sapp. - Task-3: print
s1itself, to see what a plain object looks like.
The number after 0x is a memory address, so it is different on every run. Yours will not match this one.
Need a hint?
Put app = "Tunefy" inside the class body (not in a method) so every Song shares it; create objects with Song() and read the shared value as s1.app. Printing s1 itself shows the default <...Song object at 0x...> because there is no __str__ yet.
Show the solution
# Task-1: the class, with one value shared by every Song
class Song:
app = "Tunefy"
# Task-2: create two songs and print the shared app
s1 = Song()
s2 = Song()
print(s1.app)
print(s2.app)
# Task-3: print the object itself, which shows a memory address, not data
print(s1)
Pages for this step: Concept | Practice | Workshop
Python Files for this step: Concept | Practice | Practice Solutions | Workshop | Workshop Solutions
Step-02: Give Each Object Its Own Data (__init__ and self)¶
Concepts: __init__, self, instance attributes.
Write a program with one class Song:
- Task-1: write the class with an
__init__that takes atitleand anartistand stores each onself. - Task-2: create
s1with titleYesterdayand artistThe Beatles, and print its title and artist on one line. - Task-3: create
s2with titleHelloand artistAdele, and print its own title and artist on one line.
Need a hint?
Store both values inside __init__ with self.title = title and self.artist = artist; each Song keeps its OWN attributes, so s2 (Hello / Adele) stays independent of s1 (Yesterday / The Beatles).
Show the solution
# Task-1: the class, with __init__ storing each value on self
class Song:
def __init__(self, title, artist):
self.title = title
self.artist = artist
# Task-2: create s1 and print its data
s1 = Song("Yesterday", "The Beatles")
print(s1.title, s1.artist)
# Task-3: create s2, which keeps its own data
s2 = Song("Hello", "Adele")
print(s2.title, s2.artist)
Pages for this step: Concept | Practice | Workshop
Python Files for this step: Concept | Practice | Practice Solutions | Workshop | Workshop Solutions
Step-03: Class Attributes vs Instance Attributes¶
Concepts: a class attribute shared by all, instance attributes per object, precedence.
Write a program with one class Song:
- Task-1: write the class with a class attribute
appset toTunefyand an__init__taking atitleand anartist. - Task-2: create
s1(Yesterday,The Beatles) ands2(Hello,Adele), prints1.app, then printSong.appstraight from the class. - Task-3: give
s2its ownappvalueMyTunes, then prints2.app,s1.appandSong.app, so the instance attribute wins fors2while the others stayTunefy.
Need a hint?
Set app = "Tunefy" at class level (shared by all Songs) and take title / artist in __init__ (one per object). Assigning s2.app = "MyTunes" makes an INSTANCE attribute that shadows the class one for s2 only, so s1.app and Song.app stay Tunefy.
Show the solution
# Task-1: the class, with a shared class attribute and per-object data
class Song:
app = "Tunefy"
def __init__(self, title, artist):
self.title = title
self.artist = artist
# Task-2: both songs, then the class attribute read from the object and from the class
s1 = Song("Yesterday", "The Beatles")
s2 = Song("Hello", "Adele")
print(s1.app)
print(Song.app)
# Task-3: an instance attribute on s2 wins for s2 only
s2.app = "MyTunes"
print(s2.app)
print(s1.app)
print(Song.app)
Pages for this step: Concept | Practice | Workshop
Python Files for this step: Concept | Practice | Practice Solutions | Workshop | Workshop Solutions
Step-04: Adding Behavior with Methods¶
Concepts: a method uses self, a method changes data, returning vs acting.
Write a program with one class Song:
- Task-1: write the class with an
__init__that takes atitleand anartistand setsself.playsto0, a methodplaythat adds1toself.plays, and a methodlabelthat RETURNS the text<title> by <artist>. - Task-2: create
s1forYesterdaybyThe Beatles, play it3times, and prints1.plays. - Task-3: print
s1.label().
Need a hint?
A method takes self first: play ACTS (self.plays = self.plays + 1, no return), while label RETURNS an f-string f"{self.title} by {self.artist}". Call s1.play() three times, then print(s1.plays) and print(s1.label()).
Show the solution
# Task-1: the class, with play() that ACTS and label() that RETURNS
class Song:
def __init__(self, title, artist):
self.title = title
self.artist = artist
self.plays = 0
def play(self):
self.plays += 1
def label(self):
return f"{self.title} by {self.artist}"
# Task-2: create the song, play it three times, then print the changed counter
s1 = Song("Yesterday", "The Beatles")
s1.play()
s1.play()
s1.play()
print(s1.plays)
# Task-3: print what label() RETURNS
print(s1.label())
Pages for this step: Concept | Practice | Workshop
Python Files for this step: Concept | Practice | Practice Solutions | Workshop | Workshop Solutions
Step-05: Readable Objects: __str__ and __repr__¶
Concepts: __str__ for a friendly printout, __repr__ for the exact one; both are dunder methods, so the name must match exactly.
Write a program with one class Song:
- Task-1: write the class with an
__init__that takes atitleand anartist,__str__returning<title> by <artist>, and__repr__returningSong(title='<title>', artist='<artist>'). - Task-2: create
s1(Yesterday,The Beatles) ands2(Hello,Adele), and prints1. - Task-3: print a list holding both songs.
Yesterday by The Beatles
[Song(title='Yesterday', artist='The Beatles'), Song(title='Hello', artist='Adele')]
Need a hint?
__str__ returns the friendly f"{self.title} by {self.artist}" that print(s1) shows; __repr__ returns the exact Song(title='...', artist='...') form (build it with an f-string) that a list [s1, s2] shows for each item. Both dunder names need the double underscores on each side.
Show the solution
# Task-1: the class, with both dunder methods
class Song:
def __init__(self, title, artist):
self.title = title
self.artist = artist
def __str__(self):
return f"{self.title} by {self.artist}"
def __repr__(self):
return f"Song(title={self.title!r}, artist={self.artist!r})"
# Task-2: create both songs; print() uses __str__
s1 = Song("Yesterday", "The Beatles")
s2 = Song("Hello", "Adele")
print(s1)
# Task-3: a list of objects uses __repr__
print([s1, s2])
Pages for this step: Concept | Practice | Workshop
Python Files for this step: Concept | Practice | Practice Solutions | Workshop | Workshop Solutions
Step-06: Class Methods and Static Methods (@classmethod and @staticmethod)¶
Concepts: the decorators @classmethod (an alternate constructor: it receives the class as cls) and @staticmethod (a related helper: it takes neither self nor cls), and using both together.
Write a program with one class Song:
- Task-1: write the class with an
__init__that takes atitle, anartistand adurationin seconds, a@classmethodfrom_dict(cls, data)that builds aSongfrom a dict with keystitle,artistandduration, and a@staticmethodis_valid_duration(duration)that returnsTruewhendurationis above0. - Task-2: print
Song.is_valid_duration(125). - Task-3: take the two dicts
{"title": "Yesterday", "artist": "The Beatles", "duration": 125}and{"title": "Silence", "artist": "Unknown", "duration": 0}. For each one, build the song withfrom_dictand print its title and duration only whenis_valid_durationsays the duration is valid, and printDuration is not validwhen it is not.
Need a hint?
@staticmethod is_valid_duration(duration) takes no self / cls, so it can simply return duration > 0, and it is called through the class as Song.is_valid_duration(125). @classmethod from_dict(cls, data) receives the class as cls, so return cls(data["title"], data["artist"], data["duration"]) builds a Song. Loop over the two dicts; inside the loop call the helper on data["duration"] in an if, build and print (.title and .duration) when it says True, and print the Duration is not valid line in the else.
Show the solution
# Task-1: the class, with the two decorated methods
class Song:
def __init__(self, title, artist, duration):
self.title = title
self.artist = artist
self.duration = duration
@classmethod
def from_dict(cls, data):
return cls(data["title"], data["artist"], data["duration"])
@staticmethod
def is_valid_duration(duration):
return duration > 0
# Task-2: a static helper, no object needed
print(Song.is_valid_duration(125))
# Task-3: the helper checks first, then the alternate constructor builds the Song
songs = [{"title": "Yesterday", "artist": "The Beatles", "duration": 125},
{"title": "Silence", "artist": "Unknown", "duration": 0}]
for data in songs:
if Song.is_valid_duration(data["duration"]):
s1 = Song.from_dict(data)
print(s1.title, s1.duration)
else:
print("Duration is not valid")
Pages for this step: Concept | Practice | Workshop
Python Files for this step: Concept | Practice | Practice Solutions | Workshop | Workshop Solutions
Finished this section?
Check your work against the solutions above, then head back to the Section 13 lesson, or try the Section 13 workshop for more reps.
Prefer to learn by watching?
The full video course teaches every concept on screen and builds the projects with you, step by step.
Practice: Virtual Environments and Packaging