Goal: Learn to save and load data in JSON format.
๐ค Why Save Data at All?
Imagine: you built a game, the player played for 2 hours, scored 1000 points… and closed the program. They open it again โ everything is reset! ๐ฑ
Problem: Variables in Python only live as long as the program is running.
Solution: Save data to a file so it persists!
๐ฆ What Is JSON?
JSON (JavaScript Object Notation) is a text file format for storing data.
It looks almost like a Python dictionary:
{
"name": "Alice",
"age": 25,
"balance": 1000.50,
"transactions": ["deposit", "withdraw", "deposit"]
}
Why JSON is so popular:
- โ
Human-readable (not binary)
- โ
Supported by every programming language
- โ
Used by websites, APIs, and databases
- โ
Built-in support in Python!
๐ Python โ JSON โ Type Mapping
| Python | JSON |
|---|---|
dict |
Object {} |
list |
Array [] |
str |
String "text" |
int, float |
Number 42, 3.14 |
True, False |
true, false |
None |
null |
Example:
# Python data
data = {
"name": "Ivan",
"scores": [10, 20, 30],
"is_active": True,
"balance": None
}
# In the JSON file it will look like:
# {
# "name": "Ivan",
# "scores": [10, 20, 30],
# "is_active": true,
# "balance": null
# }
๐ Importing the json Module
import json
Core functions:
- json.dump() โ save to a file
- json.dumps() โ convert to a string
- json.load() โ load from a file
- json.loads() โ parse from a string
๐พ Saving Data โ json.dump()
Saving simple data
import json
user = {
"name": "Alice",
"age": 25,
"balance": 1000
}
# Open the file for writing and save
with open("user.json", "w", encoding="utf-8") as file:
json.dump(user, file)
print("Data saved!")
What happens:
1. open("user.json", "w") โ opens the file for writing
2. json.dump(user, file) โ writes the dictionary to the file
3. File user.json is created!
Contents of user.json:
{"name": "Alice", "age": 25, "balance": 1000}
Pretty formatting โ indent
with open("user.json", "w", encoding="utf-8") as file:
json.dump(user, file, indent=4, ensure_ascii=False)
Parameters:
- indent=4 โ indentation for readability
- ensure_ascii=False โ preserves non-ASCII characters
Result in the file:
{
"name": "Alice",
"age": 25,
"balance": 1000
}
Much more readable! ๐
๐ Loading Data โ json.load()
import json
# Open the file for reading and load
with open("user.json", "r", encoding="utf-8") as file:
user = json.load(file)
print(user["name"]) # Alice
print(user["balance"]) # 1000
What happens:
1. Opens the file in read mode "r"
2. json.load(file) โ reads and converts to a Python dict
3. Work with the data like a regular dict!
๐ก๏ธ Safe Loading with try/except
Problem: The file might not exist!
import json
try:
with open("user.json", "r", encoding="utf-8") as file:
user = json.load(file)
print("Data loaded!")
except FileNotFoundError:
print("File not found! Creating a new profile.")
user = {"name": "Stranger", "age": 0, "balance": 0}
except json.JSONDecodeError:
print("File is corrupted! Using defaults.")
user = {"name": "Stranger", "age": 0, "balance": 0}
print(user)
Error types:
- FileNotFoundError โ file doesn’t exist
- json.JSONDecodeError โ file is corrupted (invalid JSON)
๐ Full Cycle: Save โ Modify โ Load
import json
# 1. Create data
user = {
"name": "Alice",
"balance": 1000,
"transactions": []
}
# 2. Save
with open("account.json", "w", encoding="utf-8") as file:
json.dump(user, file, indent=4, ensure_ascii=False)
print("Data saved!")
# 3. Load
with open("account.json", "r", encoding="utf-8") as file:
loaded_user = json.load(file)
# 4. Modify
loaded_user["balance"] += 500
loaded_user["transactions"].append("deposit +500")
# 5. Save changes
with open("account.json", "w", encoding="utf-8") as file:
json.dump(loaded_user, file, indent=4, ensure_ascii=False)
print("Changes saved!")
๐ฏ Example: Bank Account
import json
class BankAccount:
def __init__(self, name, balance=0):
self.name = name
self.balance = balance
self.transactions = []
def deposit(self, amount):
"""Deposit funds."""
self.balance += amount
self.transactions.append(f"Deposit: +{amount}")
print(f"Deposited: {amount}")
def withdraw(self, amount):
"""Withdraw funds."""
if amount > self.balance:
print("Insufficient funds!")
return
self.balance -= amount
self.transactions.append(f"Withdrawal: -{amount}")
print(f"Withdrawn: {amount}")
def save(self, filename):
"""Save the account to JSON."""
data = {
"name": self.name,
"balance": self.balance,
"transactions": self.transactions
}
with open(filename, "w", encoding="utf-8") as file:
json.dump(data, file, indent=4, ensure_ascii=False)
print(f"Account saved to {filename}")
@staticmethod
def load(filename):
"""Load an account from JSON."""
try:
with open(filename, "r", encoding="utf-8") as file:
data = json.load(file)
account = BankAccount(data["name"], data["balance"])
account.transactions = data["transactions"]
print(f"Account loaded from {filename}")
return account
except FileNotFoundError:
print("File not found!")
return None
# Usage
account = BankAccount("Alice", 1000)
account.deposit(500)
account.withdraw(200)
account.save("alice.json")
# Somewhere else in the program, or on the next run
loaded = BankAccount.load("alice.json")
print(f"Balance: {loaded.balance}")
print(f"History: {loaded.transactions}")
Contents of alice.json:
{
"name": "Alice",
"balance": 1300,
"transactions": [
"Deposit: +500",
"Withdrawal: -200"
]
}
๐ Saving a List of Objects
Task: Save several accounts to a single file.
import json
accounts = [
{"name": "Alice", "balance": 1000},
{"name": "Bob", "balance": 500},
{"name": "Charlie", "balance": 2000}
]
# Save
with open("bank.json", "w", encoding="utf-8") as file:
json.dump(accounts, file, indent=4, ensure_ascii=False)
# Load
with open("bank.json", "r", encoding="utf-8") as file:
loaded_accounts = json.load(file)
for account in loaded_accounts:
print(f"{account['name']}: {account['balance']}")
Contents of bank.json:
[
{
"name": "Alice",
"balance": 1000
},
{
"name": "Bob",
"balance": 500
},
{
"name": "Charlie",
"balance": 2000
}
]
๐ฏ Pattern: Auto-Save
class BankAccount:
def __init__(self, name, balance=0, filename=None):
self.name = name
self.balance = balance
self.filename = filename or f"{name}.json"
def _autosave(self):
"""Save automatically."""
data = {"name": self.name, "balance": self.balance}
with open(self.filename, "w", encoding="utf-8") as file:
json.dump(data, file, indent=4, ensure_ascii=False)
def deposit(self, amount):
"""Deposit with auto-save."""
self.balance += amount
self._autosave() # Save after every change!
print(f"Deposited: {amount}. Balance: {self.balance}")
def withdraw(self, amount):
"""Withdraw with auto-save."""
if amount <= self.balance:
self.balance -= amount
self._autosave() # Save!
print(f"Withdrawn: {amount}. Remaining: {self.balance}")
# Usage
account = BankAccount("Alice", 1000)
account.deposit(500) # Auto-saved!
account.withdraw(200) # Auto-saved!
Benefits:
- โ
Data is always up to date
- โ
Won’t be lost on a crash
- โ
No need to remember to call save()
๐ json.dumps() and json.loads() โ Working with Strings
dumps() โ to string
import json
data = {"name": "Alice", "age": 25}
json_string = json.dumps(data, ensure_ascii=False)
print(json_string) # {"name": "Alice", "age": 25}
print(type(json_string)) # <class 'str'>
When to use:
- Sending data over a network
- Storing in a database
- Logging
loads() โ from string
import json
json_string = '{"name": "Bob", "balance": 500}'
data = json.loads(json_string)
print(data["name"]) # Bob
print(type(data)) # <class 'dict'>
When to use:
- Receiving data from an API
- Reading from a database
- Parsing configuration
โ ๏ธ What CANNOT Be Saved to JSON
โ Functions
data = {"func": print} # Won't work!
json.dump(data, file) # TypeError!
โ Class instances (directly)
class User:
def __init__(self, name):
self.name = name
user = User("Alice")
json.dump(user, file) # TypeError: Object of type User is not JSON serializable
Solution: Convert to a dictionary first!
user_dict = {"name": user.name}
json.dump(user_dict, file) # Works!
โ Sets
data = {"numbers": {1, 2, 3}} # set is not supported
json.dump(data, file) # TypeError!
# Solution: convert to a list
data = {"numbers": list({1, 2, 3})}
๐ฏ Pattern: Config File
import json
# config.json
# {
# "app_name": "MyBank",
# "version": "1.0",
# "debug": true,
# "max_accounts": 100
# }
def load_config(filename="config.json"):
"""Load configuration."""
try:
with open(filename, "r", encoding="utf-8") as file:
return json.load(file)
except FileNotFoundError:
# Default values
return {
"app_name": "MyApp",
"version": "1.0",
"debug": False,
"max_accounts": 10
}
config = load_config()
print(f"App: {config['app_name']} v{config['version']}")
๐ฏ Pattern: JSON-Based Database
import json
class Database:
def __init__(self, filename="database.json"):
self.filename = filename
self.data = self._load()
def _load(self):
"""Load data."""
try:
with open(self.filename, "r", encoding="utf-8") as file:
return json.load(file)
except FileNotFoundError:
return {}
def _save(self):
"""Save data."""
with open(self.filename, "w", encoding="utf-8") as file:
json.dump(self.data, file, indent=4, ensure_ascii=False)
def set(self, key, value):
"""Set a value."""
self.data[key] = value
self._save()
def get(self, key, default=None):
"""Get a value."""
return self.data.get(key, default)
def delete(self, key):
"""Delete a value."""
if key in self.data:
del self.data[key]
self._save()
# Usage
db = Database()
db.set("user_alice", {"balance": 1000, "age": 25})
db.set("user_bob", {"balance": 500, "age": 30})
alice = db.get("user_alice")
print(alice) # {'balance': 1000, 'age': 25}
๐ JSON Security
โ ๏ธ Never store passwords in plain text!
# โ Bad
user = {
"login": "alice",
"password": "12345" # NEVER DO THIS!
}
# โ
Good โ store a hash
import hashlib
password = "12345"
password_hash = hashlib.sha256(password.encode()).hexdigest()
user = {
"login": "alice",
"password_hash": password_hash
}
โก Best Practices
โ Do:
- Use encoding=”utf-8” for non-ASCII characters
- Use indent=4 for readability
- Use ensure_ascii=False for non-ASCII text
- Wrap loads in try/except
- Validate data after loading
- Back up before overwriting
โ Don’t:
- Don’t store passwords in plain text
- Don’t serialize objects directly (use dicts/lists)
- Don’t forget encoding (you’ll get garbled text)
- Don’t ignore errors when loading
๐ Example: Full Banking System
import json
class Bank:
def __init__(self, filename="bank_data.json"):
self.filename = filename
self.accounts = self._load_accounts()
def _load_accounts(self):
"""Load all accounts."""
try:
with open(self.filename, "r", encoding="utf-8") as file:
return json.load(file)
except FileNotFoundError:
return {}
def _save_accounts(self):
"""Save all accounts."""
with open(self.filename, "w", encoding="utf-8") as file:
json.dump(self.accounts, file, indent=4, ensure_ascii=False)
def create_account(self, name, initial_balance=0):
"""Create a new account."""
if name in self.accounts:
print("Account already exists!")
return
self.accounts[name] = {
"balance": initial_balance,
"transactions": []
}
self._save_accounts()
print(f"Account {name} created! Balance: {initial_balance}")
def deposit(self, name, amount):
"""Deposit funds."""
if name not in self.accounts:
print("Account not found!")
return
self.accounts[name]["balance"] += amount
self.accounts[name]["transactions"].append(f"Deposit: +{amount}")
self._save_accounts()
print(f"Deposited: {amount}. Balance: {self.accounts[name]['balance']}")
def withdraw(self, name, amount):
"""Withdraw funds."""
if name not in self.accounts:
print("Account not found!")
return
if amount > self.accounts[name]["balance"]:
print("Insufficient funds!")
return
self.accounts[name]["balance"] -= amount
self.accounts[name]["transactions"].append(f"Withdrawal: -{amount}")
self._save_accounts()
print(f"Withdrawn: {amount}. Remaining: {self.accounts[name]['balance']}")
def show_account(self, name):
"""Display account information."""
if name not in self.accounts:
print("Account not found!")
return
account = self.accounts[name]
print(f"\n=== Account: {name} ===")
print(f"Balance: {account['balance']}")
print("Transaction history:")
for transaction in account["transactions"]:
print(f" - {transaction}")
# Usage
bank = Bank()
bank.create_account("Alice", 1000)
bank.deposit("Alice", 500)
bank.withdraw("Alice", 200)
bank.show_account("Alice")
# On the next run, data loads automatically!
๐ Summary
JSON:
- โ
A universal data storage format
- โ
Human-readable
- โ
Supported everywhere
- โ
Built into Python
Core functions:
- json.dump(data, file) โ save to a file
- json.load(file) โ load from a file
- json.dumps(data) โ convert to a string
- json.loads(string) โ parse from a string
Golden rule: Always use try/except when loading, encoding="utf-8" for text, and indent=4 for readability!
๐ Related Topics
Now your data won’t disappear when the program closes! ๐พโจ
๐ฌ Comments (0)
No comments yet
Be the first to share your opinion about this article!