Three parallel column lists — names, cats, and vals — assembled into a list of row tuples using an index loop. The trace steps through each index, building one tuple per iteration with (names[i], cats[i], vals[i]).

By hand

Walk each index from 0 to len(names) - 1 and bundle the three values at that position into a tuple. Append each tuple to rows.

naive.py
Replay: real traced execution (multi-file project)
names = ['ann', 'bob', 'cal', 'dan']
cats = ['a', 'b', 'a', 'b']
vals = [10, 20, 30, 40]
rows = []
for i in range(len(names)):
    rows.append((names[i], cats[i], vals[i]))
print('RESULT:', rows)
  1. names ← ['ann', 'bob', 'cal', 'dan']

    1names = ['ann', 'bob', 'cal', 'dan']2cats = ['a', 'b', 'a', 'b']
    values this step['ann', 'bob', 'cal', 'dan']names
  2. cats ← ['a', 'b', 'a', 'b']

    1names = ['ann', 'bob', 'cal', 'dan']2cats = ['a', 'b', 'a', 'b']3vals = [10, 20, 30, 40]
    values this step['a', 'b', 'a', 'b']cats
  3. vals ← [10, 20, 30, 40]

    2cats = ['a', 'b', 'a', 'b']3vals = [10, 20, 30, 40]4rows = []
    values this step[10, 20, 30, 40]vals
  4. rows ← []

    3vals = [10, 20, 30, 40]4rows = []5for i in range(len(names)):
    values this step[]rows
  5. i ← 0

    4rows = []5for i in range(len(names)):6    rows.append((names[i], cats[i], vals[i]))
    values this step0i
  6. rows ← [('ann', 'a', 10)]

    5for i in range(len(names)):6    rows.append((names[i], cats[i], vals[i]))7print('RESULT:', rows)
    values this step[] [('ann', 'a', 10)]rows
  7. i ← 1

    4rows = []5for i in range(len(names)):6    rows.append((names[i], cats[i], vals[i]))
    values this step0 1i
  8. rows ← [('ann', 'a', 10), ('bob', 'b', 20)]

    5for i in range(len(names)):6    rows.append((names[i], cats[i], vals[i]))7print('RESULT:', rows)
    values this step[('ann', 'a', 10)] [('ann', 'a', 10), ('bob', 'b', 20)]rows
  9. i ← 2

    4rows = []5for i in range(len(names)):6    rows.append((names[i], cats[i], vals[i]))
    values this step1 2i
  10. rows ← [('ann', 'a', 10), ('bob', 'b', 20), ('cal', 'a', 30)]

    5for i in range(len(names)):6    rows.append((names[i], cats[i], vals[i]))7print('RESULT:', rows)
    values this step[('ann', 'a', 10), ('bob', 'b', 20)] [('ann', 'a', 10), ('bob', 'b', 20), ('cal', 'a', 30)]rows
  11. i ← 3

    4rows = []5for i in range(len(names)):6    rows.append((names[i], cats[i], vals[i]))
    values this step2 3i
  12. rows ← [('ann', 'a', 10), ('bob', 'b', 20), ('cal', 'a', 30), ('dan', 'b', 40)]

    5for i in range(len(names)):6    rows.append((names[i], cats[i], vals[i]))7print('RESULT:', rows)
    values this step[('ann', 'a', 10), ('bob', 'b', 20), ('cal', 'a', 30)] [('ann', 'a', 10), ('bob', 'b', 20), ('cal', 'a', 30), ('dan', 'b', 40)]rows
  13. for i in range(len(names)):

    4rows = []5for i in range(len(names)):6    rows.append((names[i], cats[i], vals[i]))
  14. stdout ← RESULT: [('ann', 'a', 10), ('bob', 'b', 20), ('cal', 'a', 30), ('dan', 'b', 40)]

    6    rows.append((names[i], cats[i], vals[i]))7print('RESULT:', rows)
    values this stepRESULT: [('ann', 'a', 10), ('bob', 'b', 20), ('cal', 'a', 30), ('dan', 'b', 40)]stdout

The Pythonic way

zip(names, cats, vals) pairs the elements by position and returns an iterator of tuples. Wrap it in list() to materialise all rows at once.

library.py
names = ['ann', 'bob', 'cal', 'dan']
cats = ['a', 'b', 'a', 'b']
vals = [10, 20, 30, 40]
rows = list(zip(names, cats, vals))
print('RESULT:', rows)
RESULT: [('ann', 'a', 10), ('bob', 'b', 20), ('cal', 'a', 30), ('dan', 'b', 40)]

Implementation notes

  • The index loop and zip are equivalent only when all three lists have the same length. With mismatched lengths, zip silently stops at the shortest while the index loop raises IndexError. In practice, column data is generated together and is length-aligned, so zip is the safer default.
  • This operation is invertible: names, cats, vals = zip(*rows) unpacks a list of row tuples back into three separate column iterators.
  • In pandas, parallel column lists are passed as a dict to the constructor — pd.DataFrame({'name': names, 'cat': cats, 'val': vals}) — so no explicit zipping is needed.