📝 Python

`with open`: The Right Way to Work with Files 💾

0
Author
04e5cc8b-58ac-4bdc-bdee-661bbb
📅
Published
03.04.2026
⏱️
Reading time
6 min
👁️
Views
92
🌱
Level
Beginner

A game without saves is like a zombie apocalypse without a shelter: everything is lost! 😱

Learn to write data to files and read it back with with open — the proper way to handle files in Python.

🤔 Why do we need files?

The problem: data disappears

class Human:
    def __init__(self, name):
        self.name = name
        self.kills = 0

rick = Human("Rick")
rick.kills = 10

# Close the program...
# ...open it again
# Data is gone! 😱

Solution: Save to a file!

# Write to a file
with open("saves/rick.txt", "w") as f:
    f.write(f"{rick.name}\n")
    f.write(f"{rick.kills}\n")

# Close the program...
# ...open it again

# Read from the file
with open("saves/rick.txt", "r") as f:
    name = f.readline().strip()
    kills = int(f.readline().strip())

print(f"{name}: {kills} kills")  # Rick: 10 kills ✅

📝 Writing to a file: "w" mode

Syntax

with open("filename.txt", "w") as f:
    f.write("text")

"w" = write. Creates a new file or overwrites an existing one!

Example 1: Battle log

with open("battle_log.txt", "w") as f:
    f.write("=== BATTLE LOG ===\n")
    f.write("Rick attacks Walker\n")
    f.write("Damage: 20\n")
    f.write("Zombie defeated!\n")

# battle_log.txt now contains:
# === BATTLE LOG ===
# Rick attacks Walker
# Damage: 20
# Zombie defeated!

Example 2: Saving stats

class Human:
    def __init__(self, name):
        self.name = name
        self.kills = 0
        self.health = 100

    def save(self):
        with open(f"saves/{self.name}.txt", "w") as f:
            f.write(f"{self.name}\n")
            f.write(f"{self.kills}\n")
            f.write(f"{self.health}\n")
        print(f"Saved {self.name}!")

rick = Human("Rick")
rick.kills = 5
rick.save()
# Created saves/Rick.txt with the data

📖 Reading from a file: "r" mode

Syntax

with open("filename.txt", "r") as f:
    content = f.read()  # Read entire file

"r" = read.

Reading methods

1. read() — read the whole file at once

with open("battle_log.txt", "r") as f:
    content = f.read()
    print(content)
# Prints the entire file as one string

2. readline() — read one line

with open("saves/Rick.txt", "r") as f:
    name   = f.readline().strip()   # First line
    kills  = f.readline().strip()   # Second line
    health = f.readline().strip()   # Third line

print(f"{name}: {kills} kills, {health} HP")

strip() removes the trailing \n (newline character).

3. readlines() — read all lines into a list

with open("battle_log.txt", "r") as f:
    lines = f.readlines()  # ['=== BATTLE LOG ===\n', 'Rick attacks...\n', ...]

for line in lines:
    print(line.strip())  # Print each line

Example: Loading a character

class Human:
    def __init__(self, name):
        self.name = name
        self.kills = 0
        self.health = 100

    @staticmethod
    def load(name):
        """Load a character from a file."""
        with open(f"saves/{name}.txt", "r") as f:
            loaded_name = f.readline().strip()
            kills  = int(f.readline().strip())
            health = int(f.readline().strip())

        # Create an object with the loaded data
        human = Human(loaded_name)
        human.kills = kills
        human.health = health
        print(f"Loaded {loaded_name}!")
        return human

# Usage
rick = Human.load("Rick")
print(f"{rick.name}: {rick.kills} kills, {rick.health} HP")

➕ Appending to a file: "a" mode

"a" = append. Does NOT overwrite — it adds to the end!

# First write
with open("kills.txt", "w") as f:
    f.write("Kills:\n")

# Append new entries
with open("kills.txt", "a") as f:
    f.write("Rick killed Walker\n")
    f.write("Daryl killed Runner\n")

# Append another entry later
with open("kills.txt", "a") as f:
    f.write("Michonne killed Tank\n")

# File now contains:
# Kills:
# Rick killed Walker
# Daryl killed Runner
# Michonne killed Tank

Example: Battle logger

class BattleLogger:
    def __init__(self, filename):
        self.filename = filename
        # Create the file with a header
        with open(self.filename, "w") as f:
            f.write("=== BATTLE LOG ===\n\n")

    def log(self, message):
        # Append to the end of the file
        with open(self.filename, "a") as f:
            f.write(f"{message}\n")

logger = BattleLogger("battle.txt")
logger.log("Rick attacks Walker (damage: 20)")
logger.log("Walker defeated!")
logger.log("Daryl shoots Runner (damage: 50)")

🔒 Why use with?

❌ Old way (without with):

f = open("data.txt", "w")
f.write("Data")
f.close()  # ← Easy to forget!

Problems:
- ❌ You can forget to call .close()
- ❌ If an exception occurs, the file won’t be closed
- ❌ Resource leak

✅ The right way (with with):

with open("data.txt", "w") as f:
    f.write("Data")
# File closes automatically!

Benefits:
- ✅ File closes automatically (even if an exception occurs)
- ✅ Shorter and clearer
- ✅ Safer

📊 File open modes

Mode Name Behavior If file doesn’t exist
"r" read Read only Error
"w" write Write (overwrites) Creates new file
"a" append Add to end Creates new file
"r+" read+write Read and write Error
"w+" write+read Write and read (overwrites) Creates new file

Most common: "r", "w", "a"

🎮 Full example: Game with saves

class Game:
    def __init__(self):
        self.player_name = ""
        self.level = 1
        self.kills = 0
        self.health = 100

    def new_game(self, name):
        """Start a new game."""
        self.player_name = name
        self.level = 1
        self.kills = 0
        self.health = 100
        print(f"New game started: {name}")

    def save_game(self):
        """Save the game."""
        filename = f"saves/{self.player_name}_save.txt"
        with open(filename, "w") as f:
            f.write(f"{self.player_name}\n")
            f.write(f"{self.level}\n")
            f.write(f"{self.kills}\n")
            f.write(f"{self.health}\n")
        print(f"✅ Game saved: {filename}")

    def load_game(self, name):
        """Load a saved game."""
        filename = f"saves/{name}_save.txt"
        try:
            with open(filename, "r") as f:
                self.player_name = f.readline().strip()
                self.level  = int(f.readline().strip())
                self.kills  = int(f.readline().strip())
                self.health = int(f.readline().strip())
            print(f"✅ Game loaded: {filename}")
        except FileNotFoundError:
            print(f"❌ Save not found: {filename}")

    def status(self):
        """Show current status."""
        print(f"\n{'='*40}")
        print(f"Player: {self.player_name}")
        print(f"Level:  {self.level}")
        print(f"Kills:  {self.kills}")
        print(f"Health: {self.health}")
        print(f"{'='*40}\n")

# Usage
game = Game()
game.new_game("Rick")
game.kills = 10
game.level = 3
game.status()
game.save_game()

# Close the program...
# Open it again

game2 = Game()
game2.load_game("Rick")
game2.status()  # Data restored! ✅

⚠️ Common mistakes

Mistake 1: Missing mode

with open("data.txt") as f:  # ❌ No mode!
    f.write("Data")  # Error: not writable

Fix:

with open("data.txt", "w") as f:  # ✅ Specified "w"

Mistake 2: Trying to write in "r" mode

with open("data.txt", "r") as f:
    f.write("Data")  # ❌ UnsupportedOperation: not writable

Fix:

with open("data.txt", "w") as f:  # ✅ Use "w" mode

Mistake 3: Forgot .strip() when reading

with open("saves/data.txt", "r") as f:
    kills = int(f.readline())  # ❌ '10\n' → conversion error

# Fix:
kills = int(f.readline().strip())  # ✅ '10'

Mistake 4: File not found

with open("saves/data.txt", "r") as f:  # ❌ FileNotFoundError
    content = f.read()

Fix: Check existence or use try-except:

try:
    with open("saves/data.txt", "r") as f:
        content = f.read()
except FileNotFoundError:
    print("File not found!")

💡 Best practices

✅ Good:

1. Always use with

with open("data.txt", "w") as f:  # ✅ Closes automatically
    f.write("Data")

2. Organize files in subdirectories

with open("saves/player.txt", "w") as f:  # ✅ Organized

3. Use try-except when reading

try:
    with open("data.txt", "r") as f:
        content = f.read()
except FileNotFoundError:
    print("File not found")

4. Always call .strip() on read lines

name = f.readline().strip()  # ✅ Removes \n

❌ Bad:

1. Without with

f = open("data.txt", "w")  # ❌ Easy to forget close()
f.write("Data")
f.close()

2. Mixing up modes

with open("data.txt", "w") as f:
    content = f.read()  # ❌ "w" mode doesn't support reading!

📝 Checklist

  • [ ] I know why files are needed (persisting data)
  • [ ] I understand the with open(...) as f: syntax
  • [ ] I know the modes: "r" (read), "w" (write), "a" (append)
  • [ ] I can write data: f.write()
  • [ ] I can read data: f.read(), f.readline()
  • [ ] I understand why with is needed (auto-close)
  • [ ] I know to use .strip() when reading lines
  • [ ] I know how to handle FileNotFoundError

🚀 Summary

with open is the correct way to work with files.

Syntax:

# Write
with open("file.txt", "w") as f:
    f.write("data")

# Read
with open("file.txt", "r") as f:
    content = f.read()

# Append
with open("file.txt", "a") as f:
    f.write("more data")

Modes:
- "r" — read
- "w" — write (overwrites existing content)
- "a" — append (adds to the end)

Why with?
- ✅ Closes the file automatically
- ✅ Safer (closes even if an exception occurs)
- ✅ Shorter and more readable

File object methods:
- f.write(text) — write text
- f.read() — read the entire file
- f.readline() — read one line
- f.readlines() — read all lines into a list

Why do we need files?
To save progress, logs, and statistics — anything that must survive closing the program! 💾

Next step: Use files inside classes to persist objects! 🎮

Your reaction to the article

💬 Comments (0)

🔐 Sign in to leave a comment
🚪 Login
💭

No comments yet

Be the first to share your opinion about this article!

🔗 Similar

Similar articles

Continue learning with these materials

📝

Setting Up Your Environment: Python, pip, and VS …

Before writing code locally, you need to set up three tools: Python, pip, and VS...

📅 04.06.2026 👁️ 17
📝

The datetime Module: Working with Dates and Times

datetime is Python's standard module for working with dates and times. It's part of the...

📅 08.05.2026 👁️ 67
📝

.env Files and Environment Variables: Keeping Sec…

Imagine you wrote a program with an API key hardcoded in the source and pushed...

📅 08.05.2026 👁️ 76

Did you like the article?

Subscribe to our updates and receive new articles first. Grow with PyLand!