Learning Goals
3 minBy the end of this lesson you can:
- Write an
__init__method so objects arrive complete. - Say what
selfis, and why it is the first parameter. - Explain the difference between
self.nameandname. - Give an attribute a default value, and calculate one from the others.
Warm-Up · The Half-Filled Object
5 minYesterday's style, with one line missed. Which line of output appears, and where does it stop?
class Student: """One pupil in the coding club.""" mia = Student() mia.name = "Mia" mia.score = 78 ana = Student() ana.name = "Ana" print(mia.name, mia.score) print(ana.name, ana.score)
Answer
Output
Mia 78 Traceback (most recent call last): AttributeError: 'Student' object has no attribute 'score'
Ana was created successfully with no score at all. Python only complained when something tried to read it — which in a real program might be days later.
Four lines per object is tedious. Worse, the class does not say what a student is, so nothing checks that you finished. Today's fix makes the data compulsory: no name and score, no object.
New Concept · The Method That Runs Itself
12 minWhen you join the library, you do not get a card and fill it in later. You fill in the form and then they hand you the card. __init__ is that form.
class Student: """One pupil in the coding club.""" def __init__(self, name, score): self.name = name self.score = score
It is an ordinary def — indented inside the class — with three special things:
- The name.
__init__has two underscores on each side. Python calls it for you every time an object is made. Nobody typesmia.__init__(...). self. The first parameter is the brand-new object itself. Python passes it in automatically — you never write it at the call.- The assignments.
self.name = namemeans "store the value that came in as an attribute on this object".
Now creating a student is one line, and the brackets that were empty yesterday finally have a job.
mia = Student("Mia", 78) ana = Student("Ana", 65) print(mia.name, mia.score) print(ana.name, ana.score)
Output
Mia 78 Ana 65
Miss an argument and Python stops you immediately — TypeError: Student.__init__() missing 1 required positional argument: 'score'. A half-built student is no longer possible.
self.name and name are not the same thingThe one on the right is the parameter — a local, alive only while __init__ runs, exactly as you learned in FUN-05. The one on the left is an attribute on the object, which lives as long as the object does. They are usually spelled the same because that reads best, but the self. is what makes it stick.
Defaults work here too (FUN-04), and they are how you say "every new student starts with three lives".
class Student: """One pupil in the coding club.""" def __init__(self, name, score=0, lives=3): self.name = name self.score = score self.lives = lives new_pupil = Student("Hugo") print(new_pupil.name, new_pupil.score, new_pupil.lives)
Output
Hugo 0 3
Not every attribute comes from a parameter. Some you work out on the spot:
class OrderLine: """One line on a canteen order.""" def __init__(self, item, price, qty=1): self.item = item self.price = price self.qty = qty self.total = price * qty line = OrderLine("Pizza", 4.50, 2) print(line.item, line.total)
Output
Pizza 9.0
Worked Example · The Club List, Third Version
12 minThe same three pupils as yesterday. Count the lines — and count the ways to get it wrong.
class Student: """One pupil in the coding club.""" def __init__(self, name, form, score=0, lives=3): self.name = name self.form = form self.score = score self.lives = lives mia = Student("Mia", "2 Ceria", 78) wei_jie = Student("Leo", "2 Ceria", 91) ana = Student("Ana", "1 Bestari", 65) hugo = Student("Hugo", "1 Bestari") print(mia.name, "of", mia.form, "has", mia.score, "points") print(wei_jie.name, "of", wei_jie.form, "has", wei_jie.score, "points") print(ana.name, "of", ana.form, "has", ana.score, "points") print(hugo.name, "of", hugo.form, "has", hugo.score, "points") # Mia wins a round mia.score = mia.score + 10 print("After the round:", mia.name, mia.score) print("Unchanged:", wei_jie.name, wei_jie.score)
Output
Mia of 2 Ceria has 78 points Leo of 2 Ceria has 91 points Ana of 1 Bestari has 65 points Hugo of 1 Bestari has 0 points After the round: Mia 88 Unchanged: Leo 91
Hugo joined without a score, and the default gave him 0 rather than a missing attribute. Mia's ten points went to Mia alone.
class Student: and its def describe — nothing runs. Student("Mia", "2 Ceria", 78) creates a blank object, hands it to __init__ as self, runs the four assignments, and gives the finished object back to be stored in mia. That is the whole life cycle, and it happens once per pupil.
Try breaking it deliberately: call Student("Nia") with no form. The error arrives at the moment of creation, in the line you wrote — not three screens later.
Try It Yourself
13 minRewrite yesterday's Drink class with an __init__ that takes name, price, and iced defaulting to False. Make three drinks in three lines and print them.
Hint
class Drink: """One drink on the stall menu.""" def __init__(self, name, price, iced=False): self.name = name self.price = price self.iced = iced cocoa_ais = Drink("Cocoa", 3.00, True)
Write a class StallItem whose __init__ takes name, price and qty (default 1), and sets two more attributes without being asked:
self.total— price times quantity.self.label— a string such as"2 x Hot dog", built with an f-string.
Make three items and print label and total for each. Then change one item's qty after creation and print its total again. It will be wrong — write one sentence explaining why. (Lesson 3 gives you the tool to fix it.)
Mini-Challenge 🔥 · Debug: The Constructor That Never Runs
8 minElla's player class crashes on the very first object. There are three mistakes in six lines. Find them all, then say what error each one causes.
class Player:
"""One player in the game."""
def _init_(name, hp):
self.name = name
hp = hp
self.lives = 3
hero = Player("Felix", 100)
print(hero.name, "has", hero.hp, "HP")Answer
- Single underscores.
_init_is just an ordinary method with an odd name. Python never calls it, soPlayer("Felix", 100)raisesTypeError: Player() takes no arguments. It must be__init__— two each side. - No
self. The first parameter of every method is the object. Without it,namewould receive the object andselfwould not exist at all. hp = hpstores nothing. It assigns the parameter to itself and throws it away when the method ends. It must beself.hp = hp, which is whyhero.hpwould fail even after the first two fixes.
The working version:
class Player: """One player in the game.""" def __init__(self, name, hp): self.name = name self.hp = hp self.lives = 3 hero = Player("Felix", 100) print(hero.name, "has", hero.hp, "HP")
Output
Felix has 100 HP
Recap
3 min__init__ is a method Python runs for you the moment an object is created. Its first parameter, self, is that new object, and self.something = value is how data gets attached for good. Parameters may have defaults, and an attribute can be calculated rather than passed in. The class now states what one of its objects is — so a half-built object stops being possible.
Vocabulary Card
__init__- The constructor: the method Python calls automatically when an object is made.
- self
- The object the method is working on. Always the first parameter, never passed by you.
- dunder
- Short for "double underscore" — a name like
__init__that Python treats specially. - instance attribute
- A value stored on one object with
self., separate from every other object's.
Homework
4 minTake the class you wrote for OOP-01 homework and give it a proper __init__.
- At least four attributes.
- At least one with a default value, used both ways somewhere.
- At least one calculated in
__init__rather than passed in. - Create three objects in three lines, and print a tidy line for each.
Hint: good calculated attributes — a total from price and quantity, a label from two other attributes, a starting value that is always the same.
Sample · rak_buku.py
# rak_buku.py - the same shelf, now with a constructor class Book: """One book on my shelf.""" def __init__(self, title, author, price, read=False): self.title = title self.author = author self.price = price self.read = read self.label = f"{title} by {author}" sejarah = Book("Sejarah Tingkatan 2", "Kementerian Pendidikan", 12.90, True) komik = Book("Lat: Village Boy", "Lat", 24.00, True) python_book = Book("Python for Kids", "Jason Briggs", 79.90) print(sejarah.label, "- $", sejarah.price, "- read:", sejarah.read) print(komik.label, "- $", komik.price, "- read:", komik.read) print(python_book.label, "- $", python_book.price, "- read:", python_book.read)
Two books pass read=True, one takes the default. label is calculated, not asked for. Your attributes will be different — what matters is that every object is complete the moment it exists.