Slots and indexes
Line 1 makes a list of four items. Python stores them in slots that sit side by side in memory, in the order you wrote them, and keeps a note of how many there are.
Each slot has a number called its index, shown in front. Counting starts at 0, so nums[0] is the first item, 7, and nums[1] is the second. The last of four items is nums[3].
Reading is instant
Every slot is the same size, 8 bytes, so the computer works out where slot 2 is: start + index × size, here 1000 + 2 × 8 = 1016. No searching, however long the list is.
How can every slot be 8 bytes when items differ? In Python a slot holds a reference: the address of the item, which lives elsewhere in memory. That is also why one list can mix numbers and text.
Counting and slicing
A negative index counts from the end. nums[-1] is the last item, 5, and nums[-2] is the one before it. Python reads -1 as len(nums) - 1, which is 3 here.
len(nums) gives the number of items: 4. The list keeps that count in its header and updates it on every change, so len() never has to count the items one by one.
nums[1:3] is a slice: a new list made from a range of slots. It starts at index 1 and stops just before index 3, so it gives [3, 9]. The original list does not change.
Changing the list
All 4 slots are full, so append asks for room for 8, not just 5, and puts 2 in slot 4. The spare slots make the next appends cheap, so on average append takes the same short time at any length.
insert(0, 8) puts 8 at the front. First every item moves one slot right, starting from the end, to free index 0. A list of a million items needs a million moves, so this gets slower as lists grow.
A for loop visits the items in order, from index 0 to the end, giving each one to n in turn. This loop prints 8, 7, 3, 9, 5 and 2, one per line.
Try it in the Python prompt
;; step 1/10 · line 1: nums = [7, 3, 9, 5] >>> nums = [7, 3, 9, 5] >>> nums [7, 3, 9, 5] >>> type(nums) <class 'list'>
The addresses 1000, 1008, ... are made up to keep the sums easy; real addresses are much larger numbers. The rule start + index × size is how any array finds a slot. In CPython each slot holds a reference (a C pointer), 8 bytes on a 64-bit computer. The items themselves are objects stored elsewhere in memory. The exact growth is an implementation detail. In CPython 3.14 the list [7, 3, 9, 5] has room for exactly 4, and the first append grows it to room for 8 (sys.getsizeof shows 88, then 120 bytes). Growing may copy the references to a new, bigger block.