In Windows on the Python side, CreateFile can be called (directly or indirectly via the CRT) with a specific sharing mode. For example, if the desired sharing mode is FILE_SHARE_READ, then the open will fail if the file is already open for writing. If the latter call instead succeeds, then a future attempt to open the file for writing will fail (e.g. in Matlab).
The Windows CRT function _wsopen_s allows setting the sharing mode. You can call it with ctypes in a Python 3 opener:
import sys
import os
import ctypes as ctypes
import ctypes.util
__all__ = ['shdeny', 'shdeny_write', 'shdeny_read']
_SH_DENYRW = 0x10  # deny read/write mode
_SH_DENYWR = 0x20  # deny write mode
_SH_DENYRD = 0x30  # deny read
_S_IWRITE  = 0x0080  # for O_CREAT, a new file is not readonly
if sys.version_info[:2] < (3,5):
    _wsopen_s = ctypes.CDLL(ctypes.util.find_library('c'))._wsopen_s
else:
    # find_library('c') may be deprecated on Windows in 3.5, if the 
    # universal CRT removes named exports. The following probably 
    # isn't future proof; I don't know how the '-l1-1-0' suffix 
    # should be handled.
    _wsopen_s = ctypes.CDLL('api-ms-win-crt-stdio-l1-1-0')._wsopen_s
_wsopen_s.argtypes = (ctypes.POINTER(ctypes.c_int), # pfh
                      ctypes.c_wchar_p,             # filename
                      ctypes.c_int,                 # oflag
                      ctypes.c_int,                 # shflag
                      ctypes.c_int)                 # pmode
def shdeny(file, flags):
    fh = ctypes.c_int()
    err = _wsopen_s(ctypes.byref(fh),
                    file, flags, _SH_DENYRW, _S_IWRITE)
    if err:
        raise IOError(err, os.strerror(err), file)
    return fh.value
def shdeny_write(file, flags):
    fh = ctypes.c_int()
    err = _wsopen_s(ctypes.byref(fh),
                    file, flags, _SH_DENYWR, _S_IWRITE)
    if err:
        raise IOError(err, os.strerror(err), file)
    return fh.value
def shdeny_read(file, flags):
    fh = ctypes.c_int()
    err = _wsopen_s(ctypes.byref(fh),
                    file, flags, _SH_DENYRD, _S_IWRITE)
    if err:
        raise IOError(err, os.strerror(err), file)
    return fh.value
For example:
if __name__ == '__main__':
    import tempfile
    filename = tempfile.mktemp()
    fw = open(filename, 'w')
    fw.write('spam')
    fw.flush()
    fr = open(filename)
    assert fr.read() == 'spam'
    try:
        f = open(filename, opener=shdeny_write)
    except PermissionError:
        fw.close()
        with open(filename, opener=shdeny_write) as f:
            assert f.read() == 'spam'
    try:
        f = open(filename, opener=shdeny_read)
    except PermissionError:
        fr.close()
        with open(filename, opener=shdeny_read) as f:
            assert f.read() == 'spam'
    with open(filename, opener=shdeny) as f:
        assert f.read() == 'spam'
    os.remove(filename)
In Python 2 you'll have to combine the above openers with os.fdopen, e.g.:
f = os.fdopen(shdeny_write(filename, os.O_RDONLY|os.O_TEXT), 'r')
Or define an sopen wrapper that lets you pass the share mode explicitly and calls os.fdopen to return a Python 2 file. This will require a bit more work to get the file mode from the passed in flags, or vice versa.