083. Instance Methods
Add behavior to objects through methods
083. Instance Methods
He has a Process class with attributes. But the reporting code still lives outside as standalone functions: format_process(p), is_heavy(p, threshold). They take p as an argument — which is the Process itself.
He moves these as methods:
class Process:
def __init__(self, name, pid, rss_mb):
self.name = name
self.pid = pid
self.rss_mb = rss_mb
self.alerts = []
def is_heavy(self, threshold_mb=500):
# self already IS the process — no argument needed
return self.rss_mb > threshold_mb
def add_alert(self, message):
self.alerts.append(message)
def alert_count(self):
return len(self.alerts)
def summary(self):
flag = " [HEAVY]" if self.is_heavy() else ""
return f"{self.name}[{self.pid}]: {self.rss_mb} MB{flag}"
chrome = Process("chrome", 1234, 620)
chrome.add_alert("RAM > 500 MB")
print(chrome.summary()) # chrome[1234]: 620 MB [HEAVY]
print(chrome.alert_count()) # 1💡 Fun fact: When you call chrome.summary(), Python internally translates this to Process.summary(chrome) — passing the instance as the first argument automatically. This is why self must always be the first parameter: Python is literally passing the object to its own method. You can actually call it this “unbound” way manually: Process.summary(chrome) works identically.
⚠️ Watch out: The most common instance method mistake is referencing balance instead of self.balance inside a method. Without self., Python looks for a local variable named balance — which doesn’t exist — and raises UnboundLocalError. The self. prefix is not optional boilerplate; it’s the only way to reach instance state.
🤔 Think about it: Instance methods receive self implicitly, but Python also has @staticmethod (no self) and @classmethod (receives the class, not an instance). When would you choose a static method over a standalone module-level function? What does the choice communicate to readers of your code?
Learning objectives
- Define instance methods that read and modify attributes
- Call methods on instances
- Implement methods that return computed values
Key concepts
- instance methods
- self
- method calls
- state mutation
Try it
Concept detail
Instance methods are functions defined inside a class that receive self as the first parameter — giving them access to the instance’s attributes.
class TaskList:
def add(self, title): # called as tl.add("Buy milk")
self.tasks.append(...) # Python passes tl as self automatically
def pending_count(self): # called as tl.pending_count()
return sum(...)self is implicit: tl.add(“Buy milk”) passes tl as self behind the scenes. You never pass self explicitly when calling a method.
Methods can:
- Read instance attributes (self.tasks)
- Modify instance attributes (self.tasks.append(…))
- Return computed values (return sum(…))
- Call other methods on self (self.add(“x”) inside another method)
WHY methods instead of standalone functions: # Standalone function — must pass the object: def pending_count(tl): return sum(1 for t in tl.tasks if not t[“done”])
# Method — self already IS the object:
def pending_count(self):
return sum(1 for t in self.tasks if not t["done"])Methods are the “verbs” of a class — what the object can DO. Attributes are the “nouns” — what the object HAS.
Solution
class TaskList:
def __init__(self):
self.tasks = []
def add(self, title):
self.tasks.append({"title": title, "done": False})
def complete(self, title):
for task in self.tasks:
if task["title"] == title:
task["done"] = True
return True
return False
def pending_count(self):
return sum(1 for t in self.tasks if not t["done"])
def summary(self):
done = sum(1 for t in self.tasks if t["done"])
return f"{done}/{len(self.tasks)} tasks done"Tests
def test_add_task():
tl = TaskList()
tl.add("Buy milk")
assert len(tl.tasks) == 1
assert tl.tasks[0]["title"] == "Buy milk"
assert tl.tasks[0]["done"] == False
def test_complete_task():
tl = TaskList()
tl.add("Read docs")
result = tl.complete("Read docs")
assert result == True
assert tl.tasks[0]["done"] == True
def test_complete_missing():
tl = TaskList()
tl.add("Buy milk")
assert tl.complete("Nonexistent") == False
def test_pending_count():
tl = TaskList()
tl.add("A")
tl.add("B")
tl.add("C")
tl.complete("A")
assert tl.pending_count() == 2
def test_pending_count_all_done():
tl = TaskList()
tl.add("X")
tl.complete("X")
assert tl.pending_count() == 0
def test_summary():
tl = TaskList()
tl.add("X")
tl.add("Y")
tl.complete("X")
assert tl.summary() == "1/2 tasks done"