{"id":"code-col-py-mutable-default-trace","audience":"college","category":"coding","track":"coding","technique":"format","title":"See exactly what a mutable default argument does","free":false,"task":"Your helper returns lists you didn't expect. Ask for exactly 4 numbered lines, one per print call, in the form 'Call 1 prints [...]', then one unnumbered line starting 'Why:' under 25 words. You want to fix it yourself, so no corrected code and no code blocks. Under 80 words in total.","materialLabel":"Your code and its output (attached to your prompt automatically)","material":"# todo.py  - small to-do helper for my Intro to Software Dev side project\n\ndef add_tag(tag, tags=[]):\n    tags.append(tag)\n    return tags\n\nprint(add_tag(\"urgent\"))\nprint(add_tag(\"later\"))\nprint(add_tag(\"home\", [\"work\"]))\nprint(add_tag(\"errand\"))\n\n# What I expected:\n#   ['urgent']\n#   ['later']\n#   ['work', 'home']\n#   ['errand']\n#\n# What I got: the 1st and 3rd lines look right, but the others have\n# extra tags in them and I can't figure out where they come from.\n#\n# Things I checked:\n#   - I'm not using a global variable anywhere\n#   - I restarted VS Code\n#   - Python 3.12.1\n#\n# Prof said we'd cover \"how Python evaluates default arguments\" next\n# week, not sure if related.","rules":[{"type":"numberedItems","count":4},{"type":"codeBlocks","count":0},{"type":"maxProseWords","max":80}],"mistakes":[{"title":"Getting the fix handed over","why":"The AI's default is the tags=None pattern, which skips understanding why.","fix":"Say: \"Don't give me corrected code; I'll fix it myself.\"","checks":["r2","codeBlocks"]},{"title":"No trace","why":"Without each call's output, you can't see the list growing.","fix":"Ask: \"One line per call: Call 1 prints [...].\"","checks":["r0","numberedItems"]},{"title":"A long lecture","why":"The AI explains default arguments, mutability and best practices at length.","fix":"Add: \"Then one 'Why:' line under 25 words.\"","checks":["r1","maxProseWords"]}],"promptHints":[{"label":"Asks for a trace","patterns":["call 1","one (line )?per (call|print)","each call"]},{"label":"Sets the number of lines","patterns":["\\b(4|four)\\b.{0,15}line","numbered"]},{"label":"Asks for a short why","patterns":["why:","\\d+\\s*words"]},{"label":"Rules out the fix","patterns":["don'?t (give|write|show).{0,20}(fix|code)","no (corrected|fixed) code","myself"]}],"hint":"Seeing the list grow call by call explains the bug better than a paragraph. Ask for that trace, one short reason, and no fix.","rubricLabels":["The 4 lines say call 1 prints ['urgent'], call 2 prints ['urgent', 'later'], call 3 prints ['work', 'home'] and call 4 prints ['urgent', 'later', 'errand'], in the form 'Call N prints [...]'","The Why: line says the default list is created once, when def runs, and is shared by calls that don't pass a list (call 3 passed its own)","There is no corrected code (no 'tags=None' fix written out) and no code block"]}