The file.readable() method returns a boolean True if the underlying file stream was opened with read capabilities, and False otherwise.
Defensive Programming Guard: Calling read() or readline() on a write-only stream (such as mode 'w' or 'a') crashes your application with an io.UnsupportedOperation: not readable exception. Verifying stream.readable() allows data pipelines to inspect permissions gracefully before performing I/O.
The standard CPython signature for file.readable() is:
file_object.readable()
| Component | Type | Parameters? | Behavior & Description |
|---|---|---|---|
| Arguments | None | None | readable() accepts no parameters. Passing arguments raises TypeError. |
| Return Value | bool |
— | Returns True if the stream was opened with read permissions; returns False if opened in write-only or append-only modes. |
| Exceptions | ValueError |
— | Raised with I/O operation on closed file if called on an already closed stream. |
Whether a file stream returns True or False depends entirely on the access mode passed during open():
| File Mode | readable() Return | writable() Return | Stream Capability Summary |
|---|---|---|---|
'r' / 'rb' |
True | False | Read-only stream; reading permitted. |
'r+' / 'r+b' |
True | True | Read-write stream; reading and writing permitted. |
'w+' / 'w+b' |
True | True | Read-write stream (file truncated upon opening). |
'a+' / 'a+b' |
True | True | Read-and-append stream (seek required to read from start). |
'w' / 'wb' |
False | True | Write-only stream; read attempts raise UnsupportedOperation. |
'a' / 'ab' |
False | True | Append-only stream; read attempts raise UnsupportedOperation. |
'x' / 'xb' |
False | True | Exclusive creation write-only stream. |
In functions that accept arbitrary file streams from external callers, calling fob.read() blindly is risky. Use readable() as a pre-flight guard:
def safe_extract_header(stream) -> str | None:
if stream.closed:
raise ValueError("Cannot read from a closed file stream.")
if not stream.readable():
print("Warning: Stream was opened without read permissions.")
return None
return stream.readline().strip()
with open("data.txt", "r", encoding="utf-8") as valid_stream:
print("Header:", safe_extract_header(valid_stream))
with open("data.txt", "a", encoding="utf-8") as write_only_stream:
print("Append stream result:", safe_extract_header(write_only_stream)) # None
Python's I/O framework uses standard protocols. In-memory buffers like io.StringIO and io.BytesIO implement readable() seamlessly, allowing polymorphic function designs:
import io
mem_buffer = io.StringIO("In-memory configuration stream")
print("Is io.StringIO readable?", mem_buffer.readable()) # True
byte_buffer = io.BytesIO(b"\x00\x01\x02\x03")
print("Is io.BytesIO readable? ", byte_buffer.readable()) # True
Attempting to query stream.readable() after the file descriptor has been closed does not return False — it raises a ValueError exception:
f = open("data.txt", "r", encoding="utf-8")
f.close()
try:
print(f.readable())
except ValueError as err:
print("Cannot inspect closed stream:", err) # ValueError: I/O operation on closed file
# Safe inspection pattern: check stream.closed first
is_usable = not f.closed and f.readable()
print("Safe usability check:", is_usable) # False
Inspect any stream object to report full capability diagnostics (read, write, seek):
def inspect_stream_capabilities(stream) -> dict[str, bool]:
if stream.closed:
return {"closed": True, "readable": False, "writable": False, "seekable": False}
return {
"closed": False,
"readable": stream.readable(),
"writable": stream.writable(),
"seekable": stream.seekable(),
}
with open("log.txt", "a") as app_log:
print("Append mode status:", inspect_stream_capabilities(app_log))
stream.readable() checks whether the Python file stream was opened in a mode that permits reading (like 'r'). It does not perform OS-level filesystem ACL checks — OS permission issues raise PermissionError during the open() call itself.
A stream returns readable() == True even after reaching the end of the file (EOF) or when the file contains zero bytes. It checks capability, not whether data remains in the stream.
Run this complete test harness verifying mode matrix compliance, closed stream handling, and defensive guards:
import tempfile
import os
class ReadableVerifier:
@staticmethod
def check_readability(stream) -> bool:
try:
return not stream.closed and stream.readable()
except ValueError:
return False
# Verification unit assertions
with tempfile.TemporaryDirectory() as td:
v = ReadableVerifier()
test_file = os.path.join(td, "verify.txt")
with open(test_file, "w", encoding="utf-8") as f:
f.write("Sample data\n")
# Test 1: Mode 'r' is readable
with open(test_file, "r", encoding="utf-8") as f:
assert f.readable() is True
assert v.check_readability(f) is True
# Test 2: Mode 'a' is NOT readable
with open(test_file, "a", encoding="utf-8") as f:
assert f.readable() is False
# Test 3: Mode 'r+' is readable
with open(test_file, "r+", encoding="utf-8") as f:
assert f.readable() is True
# Test 4: Closed stream safely handled
f_closed = open(test_file, "r", encoding="utf-8")
f_closed.close()
assert v.check_readability(f_closed) is False
print("All file.readable() unit assertions passed successfully!")
Open in Google Colab View on GitHub
Run all file readable exercises interactively, test mode matrix validation, build polymorphic stream capability inspectors, and test closed file safeguards in Google Colab.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.