pythonmatlaboct2py

Returning class object from Oct2Py


I'm trying to run a basic MATLAB script that defines a class, and get that class object returned to python. I don't know MATLAB well, and am very new to Oct2Py so I may be completely misunderstanding how to do this. Any help would be greatly appreciated.

Here is the Matlab file (taken from here)

classdef BasicClass
   properties
      Value {mustBeNumeric}
   end
   methods
      function r = roundOff(obj)
         r = round([obj.Value],2);
      end
      function r = multiplyBy(obj,n)
         r = [obj.Value] * n;
      end
   end
end

And I call this in the python script with the following

from oct2py import octave
octave.addpath(r'C:\Users\i13500020\.spyder-py3\IST')
oclass = octave.class_example(nout=1)

when I run this I get a warning that prints four times and then an error message

First:

warning: struct: converting a classdef object into a struct overrides the access restrictions defined for properties. All properties are returned, including private and protected ones.

And then:

TypeError: 'NoneType' object is not iterable

I don't have any trouble running the roundtrip example from the Oct2Py page, so I know my installation is fine


Solution

  • I've written a small work around to use custom matlab classes with oct2py. Currently, this approach supports only access to member functions (and not attributes) of the Matlab class as this was what I needed:

    from oct2py import octave
    
    class MatlabClass():
        _counter = 0
        def __init__(self, objdef) -> None:
            """Use matlab object as python class.
    
            Args:
                objdef (str): Class initialization as string.
            """
            MatlabClass._counter += 1
            self.name = f"object_for_python{MatlabClass._counter}"
            octave.eval(f"{self.name} = {objdef};")
        
        def __getattr__(self, item):
            """Maps values to attributes.
            Only called if there *isn't* an attribute with this name
            """
            def f(*args):
                call = f"{self.name}.{item}({','.join([str(arg) for arg in args])});"
                return octave.eval(call)
            return f
    

    use this class as followed:

    param = 0.24 # random value you might need for class initialization
    oclass = MatlabClass(f"BasicClass({param})")
    x = oclass.roundOff()
    y = oclass.multiplyBy(2)
    

    Note: you might need an init function in your octave code to run set your Value variable.