Exercise 1: num_pages() on a Brand-New, Then a One-Page, File — Possible Solution ==================================================================== THE TEST ------------------------------ hf = HeapFile(path) # a genuinely new file hf.num_pages() page_num = hf.allocate_page() hf.num_pages() RESULT ------------------------------ num_pages() before allocating anything -> 0 page_num returned by allocate_page() -> 0 num_pages() after allocating one page -> 1 WHY THE COUNTS COME OUT THIS WAY ------------------------------ HeapFile.__init__ creates the file if it doesn't already exist via `open(path, 'wb').close()` -- this produces a real, valid, but completely EMPTY file (0 bytes) on disk. num_pages() is defined as: def num_pages(self): self.file.seek(0, os.SEEK_END) return self.file.tell() // PAGE_SIZE Seeking to the end of a 0-byte file and asking for the current position returns 0; 0 // PAGE_SIZE is 0 regardless of what PAGE_SIZE actually is. So a brand-new file correctly reports 0 pages -- there is genuinely nothing there yet. allocate_page() is defined as: def allocate_page(self): page_num = self.num_pages() # 0, since the file is still empty self.write_page(page_num, Page()) # writes PAGE_SIZE fresh bytes at offset 0 return page_num Calling it once: page_num is computed as the CURRENT num_pages() (0) BEFORE any new page is written -- so the very first page allocated is always page 0, matching real, zero-indexed page numbering. write_page then seeks to byte offset 0 * PAGE_SIZE = 0 and writes a full, PAGE_SIZE-byte fresh Page's own bytes there, growing the file from 0 bytes to exactly PAGE_SIZE bytes. The next call to num_pages() now sees a file of size PAGE_SIZE, and PAGE_SIZE // PAGE_SIZE = 1. WHY THIS WORKS AS AN ANSWER ------------------------------ This confirms num_pages() is never tracked as a separate counter that could drift out of sync with reality -- it's always computed directly from the REAL file size on disk, divided by PAGE_SIZE. Since every page is written as a complete, fixed PAGE_SIZE-byte block (Page's own __init__ always creates a full-size bytearray, even before any records are added), the file's own size is always guaranteed to be an exact multiple of PAGE_SIZE, making this division always come out clean, with no remainder to worry about or round incorrectly.