{"course":{"slug":"python-for-ai","title":"Python, from Zero, for AI","url":"https://addaly.com/learn/python-for-ai","level":"beginner","track":"build"},"lesson":{"slug":"files","title":"Files, and keeping data after the program ends","url":"https://addaly.com/learn/python-for-ai/files","position":39,"of":89,"minutes":7,"answer":"Opening a file with mode w empties it first, so use a when you mean to add.","keyIdea":"Opening a file with mode w empties it first, so use a when you mean to add."},"body":{"format":"markdown","text":"## Everything so far vanished\n\nEvery value you have made lived in memory and disappeared the moment the program ended. Files are how a program keeps something.\n\n```python\nwith open(\"notes.txt\", \"w\", encoding=\"utf-8\") as f:\n    f.write(\"first line\\n\")\n    f.write(\"second line\\n\")\n```\n\nRun that and a file called `notes.txt` appears next to your script. Three parts of that line matter.\n\n**The mode.** `\"w\"` means write. `\"r\"` means read, and is the default if you leave it out. `\"a\"` means append.\n\n**`encoding=\"utf-8\"`.** This says how characters are turned into bytes. Leave it out and Python 3.14 and earlier use your system's locale encoding: usually UTF-8 on macOS and Linux, often cp1252 on Windows, where writing Hindi, Chinese or emoji raises an error and reading a UTF-8 file can garble it. Python 3.15 makes UTF-8 the default. Always pass it anyway, so the same code behaves the same on every version and every machine. It costs you nothing and saves a whole class of bug involving names, accents and scripts that are not Latin.\n\n**`with`.** A file has to be closed, or your writes may sit in a buffer and never reach the disk. `with` closes it for you when the indented block ends, including when an error is thrown inside. Use `with` and stop thinking about it.\n\n## Writing empties the file first\n\n```python\nwith open(\"notes.txt\", \"w\", encoding=\"utf-8\") as f:\n    f.write(\"only this\\n\")\n```\n\nRun that twice and the file still contains one line. Mode `\"w\"` truncates: it empties the file before the first write. It does this even if you never write anything. To add without destroying, use `\"a\"`:\n\n```python\nwith open(\"notes.txt\", \"a\", encoding=\"utf-8\") as f:\n    f.write(\"added later\\n\")\n```\n\nAlso: `write` does not add a line break. If you want lines, put `\\n` yourself.\n\n## Reading\n\n```python\nwith open(\"notes.txt\", encoding=\"utf-8\") as f:\n    text = f.read()\nprint(text)\nprint(len(text))\n```\n\n`read()` gives the whole file as one string. Fine for something small, wasteful for a large log. To go line by line, loop over the file itself:\n\n```python\nwith open(\"notes.txt\", encoding=\"utf-8\") as f:\n    for line in f:\n        print(line.strip())\n```\n\nEach `line` still carries its `\\n` at the end, which is why `.strip()` is there. Without it, `print` adds a second break and everything looks double spaced.\n\n## Where is the file\n\n```\nFileNotFoundError: [Errno 2] No such file or directory: 'notes.txt'\n```\n\nA plain filename is relative to the folder your terminal is in when you run the command, not the folder the script is saved in. Those are often different. Check with `pwd` on macOS or Linux, `cd` on Windows, or from inside Python:\n\n```python\nimport os\nprint(os.getcwd())\n```\n\n## JSON, for structured data\n\nText files are fine for lines of prose. When you want to save a dict or a list, use JSON: a text format that most of the world's software, including every AI API, agrees on.\n\n```python\nimport json\n\ndata = {\"name\": \"Amara\", \"city\": \"Kano\", \"marks\": [78, 81, 92]}\n\nwith open(\"student.json\", \"w\", encoding=\"utf-8\") as f:\n    json.dump(data, f, ensure_ascii=False, indent=2)\n\nwith open(\"student.json\", encoding=\"utf-8\") as f:\n    back = json.load(f)\n\nprint(type(back))       # <class 'dict'>\nprint(back[\"marks\"][1]) # 81\n```\n\n`json.dump` writes a dict to a file. `json.load` reads it back as a real dict. `ensure_ascii=False` keeps non-English characters readable in the file instead of turning them into escape codes. `indent=2` makes it pleasant for a human to open.\n\nThe two you will use in lesson ten are the string versions: `json.dumps(data)` turns a dict into a string, `json.loads(text)` turns a string back into a dict. That is exactly what travels over the internet when you call an API.\n\n## Try this now\n\n```python\nwith open(\"log.txt\", \"a\", encoding=\"utf-8\") as f:\n    f.write(\"ran once\\n\")\n\nwith open(\"log.txt\", encoding=\"utf-8\") as f:\n    lines = f.readlines()\n\nprint(f\"{len(lines)} runs so far\")\n```\n\nRun it four times."},"check":{"question":"A script's only job is `with open(\"log.txt\", \"w\", encoding=\"utf-8\") as f: f.write(\"ran\\n\")`. You run it three times, then open the file. What is in it?","options":[{"text":"Three lines, because writing to a file means adding to what is already stored there.","correct":false,"tempting":"Writing in a notebook adds to the page, and nothing in the code says anything about erasing, so growth is the natural expectation."},{"text":"One line, because mode `\"w\"` empties the file before writing, on every run.","correct":true},{"text":"The second run stops with an error, because the file already exists and `\"w\"` is for creating a new file.","correct":false,"tempting":"`\"w\"` did create the file the first time, so it is reasonable to read it as a create instruction that should object to an existing file."},{"text":"One line, because each call to `write` replaces whatever the previous call to `write` put there.","correct":false,"tempting":"You end up with one line and only one `write` call, so blaming `write` rather than the mode explains the result just as well."}]},"prev":{"slug":"debugging-with-ai","title":"Debugging with an AI assistant, and what it gets wrong","url":"https://addaly.com/learn/python-for-ai/debugging-with-ai"},"next":{"slug":"paths-and-pathlib","title":"Paths: why your program cannot find a file that is right there","url":"https://addaly.com/learn/python-for-ai/paths-and-pathlib"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Files, and keeping data after the program ends', in Python, from Zero, for AI. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/python-for-ai/files (Accessed: 31 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Files, and keeping data after the program ends","courseTitle":"Python, from Zero, for AI","module":{"index":5,"slug":"files-formats-environments","title":"Data in and out: files, formats and the environment"},"answer":null,"keyIdea":"Opening a file with mode w empties it first, so use a when you mean to add.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"everything-so-far-vanished","runs":[{"text":"Everything so far vanished"}]},{"t":"p","runs":[{"text":"Every value you have made lived in memory and disappeared the moment the program ended. Files are how a program keeps something."}]},{"t":"code","lang":"python","label":"Python","text":"with open(\"notes.txt\", \"w\", encoding=\"utf-8\") as f:\n    f.write(\"first line\\n\")\n    f.write(\"second line\\n\")"},{"t":"p","runs":[{"text":"Run that and a file called "},{"text":"notes.txt","code":true},{"text":" appears next to your script. Three parts of that line matter."}]},{"t":"p","runs":[{"text":"The mode.","b":true},{"text":" "},{"text":"\"w\"","code":true},{"text":" means write. "},{"text":"\"r\"","code":true},{"text":" means read, and is the default if you leave it out. "},{"text":"\"a\"","code":true},{"text":" means append."}]},{"t":"p","runs":[{"text":"encoding=\"utf-8\"","b":true,"code":true},{"text":".","b":true},{"text":" This says how characters are turned into bytes. Leave it out and Python 3.14 and earlier use your system’s locale encoding: usually UTF-8 on macOS and Linux, often cp1252 on Windows, where writing Hindi, Chinese or emoji raises an error and reading a UTF-8 file can garble it. Python 3.15 makes UTF-8 the default. Always pass it anyway, so the same code behaves the same on every version and every machine. It costs you nothing and saves a whole class of bug involving names, accents and scripts that are not Latin."}]},{"t":"p","runs":[{"text":"with","b":true,"code":true},{"text":".","b":true},{"text":" A file has to be closed, or your writes may sit in a buffer and never reach the disk. "},{"text":"with","code":true},{"text":" closes it for you when the indented block ends, including when an error is thrown inside. Use "},{"text":"with","code":true},{"text":" and stop thinking about it."}]},{"t":"h2","id":"writing-empties-the-file-first","runs":[{"text":"Writing empties the file first"}]},{"t":"code","lang":"python","label":"Python","text":"with open(\"notes.txt\", \"w\", encoding=\"utf-8\") as f:\n    f.write(\"only this\\n\")"},{"t":"p","runs":[{"text":"Run that twice and the file still contains one line. Mode "},{"text":"\"w\"","code":true},{"text":" truncates: it empties the file before the first write. It does this even if you never write anything. To add without destroying, use "},{"text":"\"a\"","code":true},{"text":":"}]},{"t":"code","lang":"python","label":"Python","text":"with open(\"notes.txt\", \"a\", encoding=\"utf-8\") as f:\n    f.write(\"added later\\n\")"},{"t":"p","runs":[{"text":"Also: "},{"text":"write","code":true},{"text":" does not add a line break. If you want lines, put "},{"text":"\\n","code":true},{"text":" yourself."}]},{"t":"h2","id":"reading","runs":[{"text":"Reading"}]},{"t":"code","lang":"python","label":"Python","text":"with open(\"notes.txt\", encoding=\"utf-8\") as f:\n    text = f.read()\nprint(text)\nprint(len(text))"},{"t":"p","runs":[{"text":"read()","code":true},{"text":" gives the whole file as one string. Fine for something small, wasteful for a large log. To go line by line, loop over the file itself:"}]},{"t":"code","lang":"python","label":"Python","text":"with open(\"notes.txt\", encoding=\"utf-8\") as f:\n    for line in f:\n        print(line.strip())"},{"t":"p","runs":[{"text":"Each "},{"text":"line","code":true},{"text":" still carries its "},{"text":"\\n","code":true},{"text":" at the end, which is why "},{"text":".strip()","code":true},{"text":" is there. Without it, "},{"text":"print","code":true},{"text":" adds a second break and everything looks double spaced."}]},{"t":"h2","id":"where-is-the-file","runs":[{"text":"Where is the file"}]},{"t":"code","lang":"","label":"Text","text":"FileNotFoundError: [Errno 2] No such file or directory: 'notes.txt'"},{"t":"p","runs":[{"text":"A plain filename is relative to the folder your terminal is in when you run the command, not the folder the script is saved in. Those are often different. Check with "},{"text":"pwd","code":true},{"text":" on macOS or Linux, "},{"text":"cd","code":true},{"text":" on Windows, or from inside Python:"}]},{"t":"code","lang":"python","label":"Python","text":"import os\nprint(os.getcwd())"},{"t":"h2","id":"json-for-structured-data","runs":[{"text":"JSON, for structured data"}]},{"t":"p","runs":[{"text":"Text files are fine for lines of prose. When you want to save a dict or a list, use JSON: a text format that most of the world’s software, including every AI API, agrees on."}]},{"t":"code","lang":"python","label":"Python","text":"import json\n\ndata = {\"name\": \"Amara\", \"city\": \"Kano\", \"marks\": [78, 81, 92]}\n\nwith open(\"student.json\", \"w\", encoding=\"utf-8\") as f:\n    json.dump(data, f, ensure_ascii=False, indent=2)\n\nwith open(\"student.json\", encoding=\"utf-8\") as f:\n    back = json.load(f)\n\nprint(type(back))       # <class 'dict'>\nprint(back[\"marks\"][1]) # 81"},{"t":"p","runs":[{"text":"json.dump","code":true},{"text":" writes a dict to a file. "},{"text":"json.load","code":true},{"text":" reads it back as a real dict. "},{"text":"ensure_ascii=False","code":true},{"text":" keeps non-English characters readable in the file instead of turning them into escape codes. "},{"text":"indent=2","code":true},{"text":" makes it pleasant for a human to open."}]},{"t":"p","runs":[{"text":"The two you will use in lesson ten are the string versions: "},{"text":"json.dumps(data)","code":true},{"text":" turns a dict into a string, "},{"text":"json.loads(text)","code":true},{"text":" turns a string back into a dict. That is exactly what travels over the internet when you call an API."}]},{"t":"h2","id":"try-this-now","runs":[{"text":"Try this now"}],"role":"try"},{"t":"code","lang":"python","label":"Python","text":"with open(\"log.txt\", \"a\", encoding=\"utf-8\") as f:\n    f.write(\"ran once\\n\")\n\nwith open(\"log.txt\", encoding=\"utf-8\") as f:\n    lines = f.readlines()\n\nprint(f\"{len(lines)} runs so far\")"},{"t":"p","runs":[{"text":"Run it four times."}]}],"check":{"question":[{"text":"A script’s only job is "},{"text":"with open(\"log.txt\", \"w\", encoding=\"utf-8\") as f: f.write(\"ran\\n\")","code":true},{"text":". You run it three times, then open the file. What is in it?"}],"options":[{"text":[{"text":"Three lines, because writing to a file means adding to what is already stored there."}],"correct":false,"tempting":[{"text":"Writing in a notebook adds to the page, and nothing in the code says anything about erasing, so growth is the natural expectation."}]},{"text":[{"text":"One line, because mode "},{"text":"\"w\"","code":true},{"text":" empties the file before writing, on every run."}],"correct":true,"tempting":null},{"text":[{"text":"The second run stops with an error, because the file already exists and "},{"text":"\"w\"","code":true},{"text":" is for creating a new file."}],"correct":false,"tempting":[{"text":"\"w\"","code":true},{"text":" did create the file the first time, so it is reasonable to read it as a create instruction that should object to an existing file."}]},{"text":[{"text":"One line, because each call to "},{"text":"write","code":true},{"text":" replaces whatever the previous call to "},{"text":"write","code":true},{"text":" put there."}],"correct":false,"tempting":[{"text":"You end up with one line and only one "},{"text":"write","code":true},{"text":" call, so blaming "},{"text":"write","code":true},{"text":" rather than the mode explains the result just as well."}]}],"order":[0,1,3,2],"why":null},"prev":{"slug":"debugging-with-ai","title":"Debugging with an AI assistant, and what it gets wrong","minutes":8},"next":{"slug":"paths-and-pathlib","title":"Paths: why your program cannot find a file that is right there","minutes":8}}}