I’ve been working with Python’s I/O system and ran into a use-case that I believe could be improved with a small, backward-compatible extension.
The Problem
Currently, the built-in open() function is hardcoded to use io.FileIO for creating the raw binary stream. While this is perfect for most file operations, it can be limiting when you need lower-level control.
In my specific case, I needed to open a file and acquire an exclusive lock on it immediately at the raw file descriptor level:
class LockedFileIO(io.FileIO):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
fcntl.lockf(self.fileno(), fcntl.LOCK_EX)
The standard open() doesn’t expose a way to customize the RawIOBase implementation it uses internally, making this awkward without creating the entire I/O stack manually.
Proposed Solution
I propose we add optional keyword arguments to open() to specify the classes used to construct the I/O layers.
The new signature could look like:
open(file, mode='r', ..., raw_io_class=None, buffered_io_class=None, text_io_class=None)
How it would work:
-
If
raw_io_classis provided (and mode is appropriate), it would be instantiated instead ofio.FileIO. It would need to be a callable that returns aRawIOBaseinstance (e.g.,raw_io_class(file, mode, ...)). -
Similarly,
buffered_io_classcould override the default buffering logic, andtext_io_classcould override the text wrapper. If the mode necessitates using a buffered or text stream, the provided class will be used. Otherwise, the argument is safely ignored. -
The function would retain its current behavior if these arguments are
None(the default), ensuring full backward compatibility.