I have a python package and I would like to use its classes and methods in Matlab. I know that this can be done directly since Matlab 2014b. I mean all you have to do is add py. in the beginning of your statements. So far so good, however, I couldn't figure out how to deal with context managers through MATLAB, which are invoked using the with statement. For instance, assume that we have the following class in a module called app.py,
class App(object):
def __init__(self, input):
self._input = input
self._is_open = False
def __enter__(self):
self._is_open = True
# many other stuff going after this but not relevant to this problem
In Matlab, I can call this as
app = py.app.App(input);
py.getattr(app, '_is_open')
ans =
logical
0
and I see an instance of App in my workspace. However, as expected only __init__ is invoked this way but not __enter__.
So, is there a way to invoke __enter__ from Matlab, as if we are calling it like with App(input) as app: in Python?
Note: I am using Python 3.5.1 and Matlab 2017b
I don't believe there is any way to invoke the __enter__ method of a Python class from MATLAB, but the __exit__ method might be implicitly called (I'll address this further below).
It's important to first consider the purpose of context managers (via the __enter__ and __exit__ methods), which is to provide a way to allocate and release resources in a scope-limited fashion, whether or not that scope is exited normally or via an error. MATLAB has a more limited means of "scoping": each function has its own workspace, and control structures like loops, conditional statements, etc. within that function all share that workspace (unlike many languages in which these control structures have their own sub-scopes).
When a workspace is exited in MATLAB, the variables it contains are cleared, but any resources that were allocated may still need to be released. This can be achieved with onCleanup objects. When they are cleared from memory, they invoke a given function for managing existing resources. An example would be opening and reading from a file:
function openFileSafely(fileName)
fid = fopen(fileName, 'r');
c = onCleanup(@() fclose(fid));
s = fread(fid);
...
end
Here, a file is opened and subsequently read from. An onCleanup object c is created that will close the file when c is cleared from memory upon exit from the function. If the file were simply closed with fclose(fid) at the end of the function, then an error exit from the function (such as during the course of reading data) would cause the file to still remain opened. Using an onCleanup object ensures that the file will be closed regardless of how the function exits. Here's an example of how this could be handled in Python:
with open('some_file', 'w') as opened_file:
opened_file.write('Hola!')
Since MATLAB has a different means of "context management" than Python, this may explain why it's not possible to access the __enter__ method. I tried with a class I knew had one: the io.FileIO class. I first looked for help:
>> py.help('io.FileIO.__enter__')
Help on method_descriptor in io.FileIO:
io.FileIO.__enter__ = __enter__(...)
It finds some help text. It's not particularly helpful, but it's there. However, when I create an object and look at its methods list, neither __enter__ nor __exit__ (nor a clear equivalent) is there:
>> fio = py.io.FileIO('test.txt');
>> methods(fio)
Methods for class py._io.FileIO:
FileIO eq ge le read readinto seek truncate writelines
char fileno gt lt readable readline seekable writable
close flush isatty ne readall readlines tell write
Methods of py._io.FileIO inherited from handle.
Methods for class handle:
addlistener eq findprop gt le ne
delete findobj ge isvalid lt notify
I did notice something interesting when I cleared the fio object, though. While the fio object still existed (with the file open), I couldn't delete or move the file, as expected. However, after issuing the command clear fio, without first closing the file, I was able to interact with the file normally. This implies that the file was automatically closed. This makes me wonder if the __exit__ method might be getting implicitly invoked, but I have yet to determine it for certain.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With