Phase: 5. OOP | Estimated time: 1.5 hours | Milestone Project: No
- Module 042 (Attributes and Methods)
By the end of this module, you will be able to:
- Explain what a constructor is and when it runs
- Write parameterized constructors
- Use default values in
__init__ - Understand what happens when a class has no
__init__ - Explain why Python passes
selfimplicitly
The constructor is where objects come to life. Understanding __init__ and self is essential to designing classes that are convenient and safe to use.
__init__ is called automatically right after the object is created. Its job is to set the initial state.
class Book:
"""Represent a book."""
def __init__(self, title, author, pages):
"""Initialize a Book instance."""
self.title = title
self.author = author
self.pages = pages
self.current_page = 1 # default, not passed inThe object lifecycle:
1. __new__() → allocates memory (rarely overridden)
2. __init__() → initializes the object
3. ... use the object ...
4. __del__() → cleanup (rarely overridden, unreliable)
Pass arguments to customize each instance:
class Point:
"""Represent a 2D point."""
def __init__(self, x, y):
"""Initialize point with coordinates."""
self.x = x
self.y = y
p1 = Point(3, 4)
p2 = Point(-1, 2)Provide sensible defaults:
class Timer:
"""A simple countdown timer."""
def __init__(self, duration=10, unit="seconds"):
"""Initialize timer with optional defaults."""
self.duration = duration
self.unit = unit
self.remaining = duration
t1 = Timer() # duration=10, unit="seconds"
t2 = Timer(30) # duration=30, unit="seconds"
t3 = Timer(60, "minutes") # duration=60, unit="minutes"class BadExample:
def __init__(self, items=[]): # BAD: shared list!
self.items = items
class GoodExample:
def __init__(self, items=None):
self.items = items if items is not None else []If you don't define __init__, Python uses the default from object. The instance is still created — you can add attributes later, but the class doesn't guarantee they exist.
class Empty:
pass
obj = Empty()
obj.name = "Added later" # works, but fragileWhen you call instance.method(arg1), Python translates it to Class.method(instance, arg1). That's why self is always the first parameter.
class Demo:
def show(self, msg):
print(f"{self}: {msg}")
d = Demo()
d.show("hello") # <__main__.Demo object at 0x...>: hello
Demo.show(d, "hello") # equivalent explicit call- Mutable default arguments: Use
Noneand initialize inside the method. - Returning from
__init__:__init__must returnNone— returning anything else raisesTypeError. - Confusing
__init__with__new__:__init__initializes;__new__creates. You almost never need__new__. - Calling the constructor wrong:
obj = MyClass()notobj = MyClass.__init__().
- Write a
class Rectanglewith__init__(self, width, height). - Add a method
area()that returnswidth * height. - Create a class
Configwith default values forhost="localhost"andport=8080. - Create instances with and without arguments and verify defaults.
- Demonstrate the mutable default trap and fix it.
__init__runs automatically when an object is created.- Parameterized constructors let you customize each instance.
- Default values make constructors flexible but avoid mutable defaults.
- Without
__init__, the class inheritsobject.__init__. - Python passes
selfimplicitly — it's the instance itself.
Continue to Module 044: Class Variables vs Instance Variables.