082. Init Constructor
Initialize object state consistently at creation time
082. Init Constructor
He writes the Process class and stores attributes with the wrong names — self.mem instead of self.rss_mb. The summary() method crashes with AttributeError: 'Process' object has no attribute 'rss_mb' every time.
He also skips validating rss_mb in __init__. A negative RSS value (from a buggy /proc parser) slips in silently.
The fix: store attributes with the right names AND validate in __init__:
class Process:
def __init__(self, name: str, pid: int, rss_mb: float):
if rss_mb < 0:
raise ValueError(f"rss_mb cannot be negative: {rss_mb}")
self.name = name # correct names
self.pid = pid
self.rss_mb = rss_mb
self.alerts = [] # default mutable state initialized here💡
__init__is the one guaranteed entry point. Every instance starts with correct, validated state — or it is never created. No “I’ll validate it later” — later never comes.
Learning objectives
- Define init to initialize all instance attributes
- Validate parameters inside init
- Distinguish between init, repr, and str
Key concepts
- init
- self
- instance attributes
- repr
Try it
Concept detail
init(self, …) is the constructor — Python calls it automatically when you create an instance: Product(“Widget”, 9.99) → init(self, “Widget”, 9.99)
Three jobs of init:
- Store parameters as instance attributes with consistent names
- Validate inputs and raise early if they are invalid
- Initialize computed or default attributes
Example: def init(self, name, price, category=“general”): if price < 0: raise ValueError(f“Price cannot be negative: {price}“) self.name = name # parameter stored with correct attribute name self.price = price self.category = category self.discount = 0.0 # default — not passed in, but always exists
WHY initialize everything in init:
- If self.discount is first set in apply_discount(), an instance that never calls apply_discount() will crash when any code tries to read self.discount
- init makes all attributes predictable and explicit
repr vs str: repr → developer-facing string: f“Product({self.name!r}, {self.price})“ str → user-facing string: print(p) uses this If only repr defined, Python uses it for str as well.
!r in f-strings adds quotes around strings: f“{self.name!r}“ → ‘Widget’ (with quotes, like in repr output)
Solution
class Product:
def __init__(self, name, price, category="general"):
if price < 0:
raise ValueError(f"Price cannot be negative: {price}")
self.name = name
self.price = price
self.category = category
self.discount = 0.0
def apply_discount(self, percent):
self.discount = percent / 100
return self.price * (1 - self.discount)
def __repr__(self):
return f"Product({self.name!r}, {self.price})"Tests
def test_product_attributes():
p = Product("Widget", 9.99)
assert p.name == "Widget"
assert p.price == 9.99
assert p.category == "general"
assert p.discount == 0.0
def test_product_custom_category():
p = Product("Gadget", 29.99, "electronics")
assert p.category == "electronics"
def test_negative_price():
with pytest.raises(ValueError):
Product("Bad", -1)
def test_apply_discount_20():
p = Product("Item", 100.0)
result = p.apply_discount(20)
assert result == 80.0
def test_apply_discount_50():
p = Product("Half", 200.0)
result = p.apply_discount(50)
assert result == 100.0
def test_repr_contains_name():
p = Product("Widget", 9.99)
r = repr(p)
assert "Widget" in r
assert "9.99" in r