Execution and Memory Checkpoint
25 min · Intermediate
Need help? Ask a tutor on WhatsApp (opens in a new tab)Fix the mistakes
The slips that cost marks in this module. Spot each one, then check the fix.
A real program uses all of this at once. This checkpoint walks through one small sensor service and then tests your choices.
Decide what an object costs
A sensor service creates millions of small readings. Each reading has a device id and a value. Ask three things: does it need new attributes later, how many will exist, and does anything need a weak reference to it.
Example 1 · A compact reading class
import sys
class Reading: __slots__ = ("device", "value")
def __init__(self, device, value): self.device = device self.value = value
class LooseReading: def __init__(self, device, value): self.device = device self.value = value
fast = Reading("d1", 20.5)loose = LooseReading("d1", 20.5)print(hasattr(fast, "__dict__"), hasattr(loose, "__dict__"))print(sys.getsizeof(fast) < sys.getsizeof(loose) + sys.getsizeof(loose.__dict__))False True True
What this code does
- The slots class has no dictionary, the plain class has one.
- The plain object needs its own size plus its dictionary, so the slots object is smaller.
- Nothing else about how you use the two objects changes.
Decide who keeps it alive
A report cache should not keep old reports alive. A list that holds reports does keep them. A weak dictionary lets an entry vanish when the last strong reference goes, even in a cycle once the collector runs.
Example 2 · A cache that does not keep reports alive
import weakref
class Report: def __init__(self, name): self.name = name
cache = weakref.WeakValueDictionary()shown = []report = Report("sales")cache["sales"] = reportshown.append(len(cache))shown.append(cache["sales"].name)del reportshown.append(len(cache))print(shown)[1, 'sales', 0]
What this code does
- The cache holds the report only weakly.
- Deleting the last strong name removed the entry as well.
- A normal dictionary would have kept the report alive forever.
Decide what a function stores
A function stores its defaults when def runs. A default list is shared by every call, and a global name costs a lookup. Read the code as Python builds it, not as it looks.
Example 3 · Finding a shared default
def log(message, history=[]): history.append(message) return len(history)
def log_safe(message, history=None): if history is None: history = [] history.append(message) return len(history)
print(log("a"), log("b"), log("c"))print(log_safe("a"), log_safe("b"), log_safe("c"))print(log.__defaults__[0])1 2 3 1 1 1 ['a', 'b', 'c']
What this code does
- The first function counts 1, 2, 3 because its list is shared.
- The safe version always counts 1.
__defaults__shows the list the first function kept.
Finish up
Mark complete & continue
Next: timeit and cProfile