61 — Project — a mini bank
Guide 48 kept a shop's money in a dict; guide
43 put the storage logic in a module. A bank account is the
same pair one step further: a dict with a balance and a history list of
every transaction, saved to account.json by a bank.nme module.
Steps
An account is one dict with two parts:
balancestarts at 0, andhistoryis a list that grows with every deposit or withdrawal. It prints100and['+100']:
run it →account = {"balance": 0, "history": []} account["balance"] = account["balance"] + 100 account["history"].append("+100") show account["balance"] show account["history"]Each transaction is one string in the history list, with a
+for deposits and a-for withdrawals.Storage lives in a module,
bank.nme, exportingload()andsave.load()returns a fresh account when no file exists yet — the same pattern as the store module in guide 48:
run it →# bank.nme — file storage for the mini bank. import os use file latest def load(): if os.path.exists("account.json"): return json_load("account.json") return {"balance": 0, "history": []} def save(account): json_save("account.json", account)json_loadreturns the saved dict, sobalanceandhistorycome back exactly as they were written.The whole bank. Save
account.nmenext tobank.nme:# account.nme — a mini bank kept in a JSON file. # Run: nme r account # Type deposit, withdraw, balance, history, or quit. from "bank.nme" import load, save account = load() show "Mini bank — balance is kept in account.json" while True: show "Commands: deposit, withdraw, balance, history, quit" ask command, "? " if command == "deposit": ask amount_text, "Amount? " amount = int(amount_text) account["balance"] = account["balance"] + amount account["history"].append(f"+{amount}") save(account) show f"Deposited {amount}" elif command == "withdraw": ask amount_text, "Amount? " amount = int(amount_text) if amount <= account["balance"]: account["balance"] = account["balance"] - amount account["history"].append(f"-{amount}") save(account) show f"Withdrew {amount}" else: show "Not enough money" elif command == "balance": show f"Balance: {account['balance']}" elif command == "history": show f"{len(account['history'])} transactions" for entry in account["history"]: show entry elif command == "quit": show "Bye!" break else: show "Unknown command"depositadds to the balance and records+amount;withdrawchecks the balance first and records-amount. Both callsave, so every change is written toaccount.jsonimmediately.historywalks the list the waylistdid in guide 31.Run it and feed the commands through a pipe.
deposit 100thenwithdraw 30leaves 70, andhistoryshows both transactions:printf 'deposit\n100\nwithdraw\n30\nbalance\nhistory\nquit\n' | nme r accountMini bank — balance is kept in account.json Commands: deposit, withdraw, balance, history, quit ? Amount? Deposited 100 Commands: deposit, withdraw, balance, history, quit ? Amount? Withdrew 30 Commands: deposit, withdraw, balance, history, quit ? Balance: 70 Commands: deposit, withdraw, balance, history, quit ? 2 transactions +100 -30 Commands: deposit, withdraw, balance, history, quit ? Bye!Look at
account.json— it now holds the whole state:
run it →{"balance": 70, "history": ["+100", "-30"]}Withdrawing more than the balance prints
Not enough moneyand saves nothing, so the account can never go negative:printf 'withdraw\n500\nbalance\nquit\n' | nme r accountMini bank — balance is kept in account.json Commands: deposit, withdraw, balance, history, quit ? Amount? Not enough money Commands: deposit, withdraw, balance, history, quit ? Balance: 70 Commands: deposit, withdraw, balance, history, quit ? Bye!
Try it yourself
Add a transfer command that withdraws from this account and deposits into a
second one — load both, change both, save both. Or refuse deposits of zero or
negative amounts with an if amount <= 0: check.
What you learned
- An account is a dict of
{balance, history};historyis a list of strings. load()/save()inbank.nmekeep the file format in one module.withdrawchecksamount <= account["balance"]before spending.- Every change calls
save, so the account survives between runs.