/* Python 3 -- Lists Create and index, access with a loop, update by index, remove with del, copy with a loop No em dashes anywhere -- use plain hyphens or rewrite the sentence. Line index comments mark each scenario's 0-based line numbers (blank lines are not counted). */ STEPPER_REGISTRY.register("python-3/lists", { label: 'Lists', panelConfig: { stack: true, heap: false, custom: false, legend: [ { color:'#1d5799', border:'#9dc0e8', label:'Currently running frame' }, { color:'#a0540a', border:'#e8c070', label:'Variable just assigned' }, { color:'#095e40', border:'#90d4b8', label:'Holding a value' }, { color:'#3d3490', border:'#b0a8e0', label:'Reference (list)' }, ] }, scenarios: [ /* ------------------------------------------------------------------ */ /* 1. Create and index */ /* */ /* 0 nums = [10, 20, 30] */ /* 1 x = nums[0] */ /* 2 y = nums[2] */ /* ------------------------------------------------------------------ */ { label: 'Create and index', lines: [ { code: [['tok-op','nums = ['],['tok-num','10'],['tok-op',', '],['tok-num','20'],['tok-op',', '],['tok-num','30'],['tok-op',']']] }, { code: [['tok-op','x = nums['],['tok-num','0'],['tok-op',']']] }, { code: [['tok-op','y = nums['],['tok-num','2'],['tok-op',']']] }, ], steps: [ { line:0, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:true,cls:true}],active:true}], expl:{label:'List created', text:'nums = [10, 20, 30] creates a 3-element list. nums holds a reference to it. The purple pill signals it is a reference, not a primitive value.'} }, { line:1, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'x',v:'10',fresh:true,cls:false}],active:true}], expl:{label:'Reading index 0', text:'nums[0] reads the element at index 0. Lists are zero-indexed, so the first element is 10. That value is copied into x.'} }, { line:2, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'x',v:'10',fresh:false,cls:false},{n:'y',v:'30',fresh:true,cls:false}],active:true}], expl:{label:'Reading index 2', text:'nums[2] reads the last element. Index 2 holds 30, which is copied into y. Valid indices for a 3-element list are 0, 1, and 2.'} }, { line:2, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'x',v:'10',fresh:false,cls:false},{n:'y',v:'30',fresh:false,cls:false}],active:true}], expl:{label:'Script ends', text:'All local variables go out of scope and the script finishes.'} }, ] }, /* ------------------------------------------------------------------ */ /* 2. Access with a loop */ /* */ /* 0 nums = [10, 20, 30] */ /* 1 total = 0 */ /* 2 for i in range(len(nums)): */ /* 3 total = total + nums[i] */ /* ------------------------------------------------------------------ */ { label: 'Access with a loop', lines: [ { code: [['tok-op','nums = ['],['tok-num','10'],['tok-op',', '],['tok-num','20'],['tok-op',', '],['tok-num','30'],['tok-op',']']] }, { code: [['tok-op','total = '],['tok-num','0']] }, { code: [['tok-kw','for '],['tok-op','i '],['tok-kw','in '],['tok-meth','range'],['tok-op','('],['tok-meth','len'],['tok-op','(nums)):']] }, { code: [['',' '],['tok-op','total = total + nums[i]']] }, ], steps: [ { line:0, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:true,cls:true}],active:true}], expl:{label:'List created', text:'nums holds a reference to a 3-element list. We will visit each element using a loop.'} }, { line:1, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'0',fresh:true,cls:false}],active:true}], expl:{label:'Accumulator initialized', text:'total = 0. Each loop iteration will read one element from nums and add it to total.'} }, { line:2, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'0',fresh:false,cls:false},{n:'i',v:'0',fresh:true,cls:false}],active:true}], expl:{label:'First value from range', text:'range(len(nums)) produces range(3). Python asks it for its first value. i = 0. It will serve as the index into nums.'} }, { line:2, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'0',fresh:false,cls:false},{n:'i',v:'0',fresh:false,cls:false}],active:true}], expl:{label:'Condition: true', text:'Python checks the range is not exhausted. 0 < 3 -- first iteration begins.'} }, { line:3, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'10',fresh:true,cls:false},{n:'i',v:'0',fresh:false,cls:false}],active:true}], expl:{label:'Read index 0', text:'nums[i] is nums[0], which is 10. total = 0 + 10 gives total = 10.'} }, { line:2, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'10',fresh:false,cls:false},{n:'i',v:'1',fresh:true,cls:false}],active:true}], expl:{label:'Next value from range', text:'Python asks the range for its next value. i = 1.'} }, { line:3, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'30',fresh:true,cls:false},{n:'i',v:'1',fresh:false,cls:false}],active:true}], expl:{label:'Read index 1', text:'nums[1] is 20. total = 10 + 20 gives total = 30.'} }, { line:2, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'30',fresh:false,cls:false},{n:'i',v:'2',fresh:true,cls:false}],active:true}], expl:{label:'Next value from range', text:'Python asks the range for its next value. i = 2.'} }, { line:3, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'60',fresh:true,cls:false},{n:'i',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'Read index 2', text:'nums[2] is 30. total = 30 + 30 gives total = 60. All elements have been visited.'} }, { line:2, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'60',fresh:false,cls:false}],active:true}], expl:{label:'range exhausted', text:'range(3) has no more values. The loop exits and i goes out of scope.'} }, { line:3, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:false,cls:true},{n:'total',v:'60',fresh:false,cls:false}],active:true}], expl:{label:'Script ends', text:'The loop visited every element once, using i as the index. The final value of total is 60: 10 + 20 + 30.'} }, ] }, /* ------------------------------------------------------------------ */ /* 3. Update by index */ /* */ /* 0 nums = [10, 20, 30] */ /* 1 nums[1] = 99 */ /* ------------------------------------------------------------------ */ { label: 'Update by index', lines: [ { code: [['tok-op','nums = ['],['tok-num','10'],['tok-op',', '],['tok-num','20'],['tok-op',', '],['tok-num','30'],['tok-op',']']] }, { code: [['tok-op','nums['],['tok-num','1'],['tok-op','] = '],['tok-num','99']] }, ], steps: [ { line:0, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:true,cls:true}],active:true}], expl:{label:'List created', text:'nums holds a reference to a 3-element list: [10, 20, 30].'} }, { line:1, stack:[{name:'',vars:[{n:'nums',v:'[10, 99, 30]',fresh:true,cls:true}],active:true}], expl:{label:'Element updated', text:'nums[1] = 99 overwrites the element at index 1. The list goes from [10, 20, 30] to [10, 99, 30]. Indices 0 and 2 are unchanged.'} }, { line:1, stack:[{name:'',vars:[{n:'nums',v:'[10, 99, 30]',fresh:false,cls:true}],active:true}], expl:{label:'Script ends', text:'The list holds [10, 99, 30] at the end.'} }, ] }, /* ------------------------------------------------------------------ */ /* 4. Remove by index (del) */ /* */ /* 0 nums = [10, 20, 30] */ /* 1 del nums[1] */ /* ------------------------------------------------------------------ */ { label: 'Remove by index', lines: [ { code: [['tok-op','nums = ['],['tok-num','10'],['tok-op',', '],['tok-num','20'],['tok-op',', '],['tok-num','30'],['tok-op',']']] }, { code: [['tok-kw','del '],['tok-op','nums['],['tok-num','1'],['tok-op',']']] }, ], steps: [ { line:0, stack:[{name:'',vars:[{n:'nums',v:'[10, 20, 30]',fresh:true,cls:true}],active:true}], expl:{label:'List created', text:'nums is [10, 20, 30]. Unlike Java arrays, Python lists are dynamic -- they can grow and shrink.'} }, { line:1, stack:[{name:'',vars:[{n:'nums',v:'[10, 30]',fresh:true,cls:true}],active:true}], expl:{label:'Element removed', text:'del nums[1] removes the element at index 1 (20). The remaining elements shift left automatically. The list shrinks from length 3 to length 2 -- no zeroing, no placeholders.'} }, { line:1, stack:[{name:'',vars:[{n:'nums',v:'[10, 30]',fresh:false,cls:true}],active:true}], expl:{label:'Script ends', text:'The list holds [10, 30]. del is unique to Python -- Java arrays require manual shifting because their size is fixed.'} }, ] }, /* ------------------------------------------------------------------ */ /* 5. Copy with a loop (append) */ /* */ /* 0 src = [1, 2, 3] */ /* 1 copy = [] */ /* 2 for item in src: */ /* 3 copy.append(item) */ /* ------------------------------------------------------------------ */ { label: 'Copy with a loop', lines: [ { code: [['tok-op','src = ['],['tok-num','1'],['tok-op',', '],['tok-num','2'],['tok-op',', '],['tok-num','3'],['tok-op',']']] }, { code: [['tok-op','copy = []']] }, { code: [['tok-kw','for '],['tok-op','item '],['tok-kw','in '],['tok-op','src:']] }, { code: [['',' '],['tok-op','copy.'],['tok-meth','append'],['tok-op','(item)']] }, ], steps: [ { line:0, stack:[{name:'',vars:[{n:'src',v:'[1, 2, 3]',fresh:true,cls:true}],active:true}], expl:{label:'Source list created', text:'src holds a reference to [1, 2, 3]. This is the list we want to copy from.'} }, { line:1, stack:[{name:'',vars:[{n:'src',v:'[1, 2, 3]',fresh:false,cls:true},{n:'copy',v:'[]',fresh:true,cls:true}],active:true}], expl:{label:'Empty destination list', text:'copy = [] creates a fresh empty list. copy is a separate list in memory -- not the same object as src.'} }, { line:2, stack:[{name:'',vars:[{n:'src',v:'[1, 2, 3]',fresh:false,cls:true},{n:'copy',v:'[]',fresh:false,cls:true},{n:'item',v:'1',fresh:true,cls:false}],active:true}], expl:{label:'First element', text:'Python takes the first element from src. item = 1.'} }, { line:3, stack:[{name:'',vars:[{n:'src',v:'[1, 2, 3]',fresh:false,cls:true},{n:'copy',v:'[1]',fresh:true,cls:true},{n:'item',v:'1',fresh:false,cls:false}],active:true}], expl:{label:'append(item)', text:'copy.append(item) adds 1 to the end of copy. copy is now [1].'} }, { line:2, stack:[{name:'',vars:[{n:'src',v:'[1, 2, 3]',fresh:false,cls:true},{n:'copy',v:'[1]',fresh:false,cls:true},{n:'item',v:'2',fresh:true,cls:false}],active:true}], expl:{label:'Next element', text:'Python takes the next element from src. item = 2.'} }, { line:3, stack:[{name:'',vars:[{n:'src',v:'[1, 2, 3]',fresh:false,cls:true},{n:'copy',v:'[1, 2]',fresh:true,cls:true},{n:'item',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'append(item)', text:'copy.append(item) adds 2. copy is now [1, 2].'} }, { line:2, stack:[{name:'',vars:[{n:'src',v:'[1, 2, 3]',fresh:false,cls:true},{n:'copy',v:'[1, 2]',fresh:false,cls:true},{n:'item',v:'3',fresh:true,cls:false}],active:true}], expl:{label:'Last element', text:'Python takes the last element from src. item = 3.'} }, { line:3, stack:[{name:'',vars:[{n:'src',v:'[1, 2, 3]',fresh:false,cls:true},{n:'copy',v:'[1, 2, 3]',fresh:true,cls:true},{n:'item',v:'3',fresh:false,cls:false}],active:true}], expl:{label:'append(item)', text:'copy.append(item) adds 3. All elements are now copied. copy is [1, 2, 3].'} }, { line:2, stack:[{name:'',vars:[{n:'src',v:'[1, 2, 3]',fresh:false,cls:true},{n:'copy',v:'[1, 2, 3]',fresh:false,cls:true}],active:true}], expl:{label:'No more elements', text:'All elements have been visited. The loop exits and item goes out of scope.'} }, { line:3, stack:[{name:'',vars:[{n:'src',v:'[1, 2, 3]',fresh:false,cls:true},{n:'copy',v:'[1, 2, 3]',fresh:false,cls:true}],active:true}], expl:{label:'Two separate lists', text:'src and copy each hold a reference to a different list object. Changing one will not affect the other.'} }, ] }, ] });