Given how dynamic Python is, I'll be shocked if this isn't somehow possible:
I would like to change the implementation of
original_stdoutWrite = sys.stdout.write
def new_stdoutWrite(*a, **kw):
original_stdoutWrite("The new one was called! ")
sys.stdout.write = new_stdoutWrite
AttributeError: 'file' object attribute 'write' is read-only
Despite its dynamicity, Python does not allow monkey-patching built-in types such as
file. It even prevents you to do so by modifying the
__dict__ of such a type — the
__dict__ property returns the dict wrapped in a read-only proxy, so both assignment to
file.write and to
file.__dict__['write'] fail. And for at least two good reasons:
the C code expects the
file built-in type to correspond to the
PyFile type structure, and
file.write to the
PyFile_Write() function used internally.
Python implements caching of attribute access on types to speed up method lookup and instance method creation. This cache would be broken if it were allowed to directly assign to type dicts.
Monkey-patching is of course allowed for classes implemented in Python which can handle dynamic modifications just fine.
However... if you really know what you are doing, you can use the low-level APIs such as
ctypes to hook into the implementation and get to the type dict. For example:
# WARNING: do NOT attempt this in production code! import ctypes def magic_get_dict(o): # find address of dict whose offset is stored in the type dict_addr = id(o) + type(o).__dictoffset__ # retrieve the dict object itself dict_ptr = ctypes.cast(dict_addr, ctypes.POINTER(ctypes.py_object)) return dict_ptr.contents.value def magic_flush_mro_cache(): ctypes.PyDLL(None).PyType_Modified(ctypes.py_object(object)) # monkey-patch file.write dct = magic_get_dict(file) dct['write'] = lambda f, s, orig_write=file.write: orig_write(f, '42') # flush the method cache for the monkey-patch to take effect magic_flush_mro_cache() # magic! import sys sys.stdout.write('hello world\n')