A.Torres
A.Torres

Reputation: 423

Returning variables Matlab and Python?

I am trying to translate some code from Matlab to Python. The start of my function (in Matlab) starts like this:

function [varargout]=hysime(varargin);
    error(nargchk(3, 4, nargin))
    if nargout > 2, error('too many output parameters'); end
    verbose = 1; % default value
    y = varargin{1}; % 1st parameter is the data set

Later in the program there is something like this:

n = varargin{2}; % the 2nd parameter is the noise
Rn = varargin{3}; % the 3rd parameter is the noise correlation matrix

if nargin == 4, verbose = ~strcmp(lower(varargin{4}),'off');end

and finally there is this:

varargout(1) = {kf};
if nargout == 2, varargout(2) = {Ek};end
return 

I am incredibly confused about what this code means. On one hand I understand that the parameters inputed all need to be returned. However, at the end of the program it appears like only 2 variables will be returned (while we input 3?). How can I translate this code so that the necessary parameters are returned? I guess my biggest issue here is that the matlab code is letting the agent input the parameters however they do not all seem required? And it seems like there cannot be more than two outputs? I am just having trouble deciphering what each line of code here means. Can someone please provide an explanation both in what is happening with the matlab code and what I can do to make the same sort of functionality in python?

Thanks!

Upvotes: 0

Views: 418

Answers (1)

TheBlackCat
TheBlackCat

Reputation: 10328

Short version

The MATLAB code should have been written like this:

function [kf, Ek]=hysime(y, n, Rn, verbose);
    error(nargchk(3, 4, nargin))
    if nargin < 4
        verbose = true;
    else
        verbose = ~strcmpi(verbose ,'off');
    end

If you know MATLAB, this should be clearer. The (mostly) corresponding Python code can be written like this:

def hysime(y, n, Rn, verbose=True):
    # rest of the function here
    return kf, Ek

Long Version

This function expects 3 or 4 input arguments, with a default value set if the fourth argument is not provided. However, it is done in a way that is much more complicated than it needs to be (although I see this pattern a lot). Ideally in MATLAB you would specify the same thing like this:

function [varargout]=hysime(y, n, Rn, verbose)
    error(nargchk(3, 4, nargin))
    if nargin < 4
        verbose = true;
    else
        verbose = ~strcmpi(verbose ,'off');
    end

So what it is doing is putting the first argument in the variable y, the second in the variable n, the third in Rn, and if the fourth is specified put it in verbose (based on how it compares to the string 'off'), otherwise set verbose to true.

In python, handling of optional arguments is built-in. You can specify default value for arguments right in the function definition by setting name=value, where name is the argument name and value is the default value. Also, for historical reasons MATLAB often uses 'on' and 'off' instead of true and false. This is almost never done in Python, people just use True and False. So you can specify the same thing in Python like so:

def hysime(y, n, Rn, verbose=True):

This makes y, n, and Rn required arguments, but lets verbose be optional.

This doesn't handle the case where verbose is set to the string 'off'. As I said, this is common in MATLAB for historical reasons, but you really shouldn't be doing it in MATLAB anymore when you can avoid it, and you definitely shouldn't be doing it in Python. But if you really, really need to handle that case, you can just do:

def hysime(y, n, Rn, verbose=True):
    if isinstance(verbose, str):
        verbose = verbose.lower() != 'off'

For the output, what the MATLAB code does is let the function either return one value or two. So someone could do this:

kf = hysime(y, n, Rn);

Or

[kf, Ek] = hysime(y, n, Rn);

However, this is also being done in a way that is more complicated than necessary. If you just return the two values, and only one return value is used, MATLAB will throw away the rest. So rather than messing around with varargout, the function could just return [kf, Ek] and MATLAB will do the same thing. An error will automatically occur if someone tries to call the function with more than 2 outputs as well, so that is also unnecessary.

Dealing with varargout in this way is only necessary if you want the program to change its behavior based on the number of outputs. In this sort of structure, the main reason you would do this is if eK was expensive to calculate, in which case you would do something like this:

varargout(1) = {kf};
if nargout == 2
    # calculate eK here
    varargout(2) = {Ek};
end

As for the return, that is only needed in MATLAB if you want to cause the function to stop early, before it reaches the end normally. Once it reaches the end normally, it will return automatically. So if the last block of code you specified is the end of the function, then the return is redundant.

So all the code you showed in MATLAB can be reduced to:

function [kf, Ek]=hysime(y, n, Rn, verbose);
    error(nargchk(3, 4, nargin))
    if nargin < 4
        verbose = true;
    else
        verbose = ~strcmpi(verbose ,'off');
    end

As for Python, as I mentioned in my other answer to you, Python requires all returned values be handled. It will never throw away returned values unless you explicitly tell it to. In your case, the simplest solution is just to have return kf, Ek at the end of the function. If someone wants both kf and Ek, they can do:

kf, Ek = hysime(y, n, Rn)

If they only want kf, they can do (where _ is the python convention for a variable you don't care about):

kf, _ = hysime(y, n, Rn)

Or:

kf = hysime(y, n, Rn)[0]

So the python code would be:

def hysime(y, n, Rn, verbose=True):
    # rest of the function here
    return kf, Ek

If you really want to be able to have one or two returned values, you would need to have another argument to change the behavior. Such as:

def hysime(y, n, Rn, verbose=True, ret_eK=False):
    # rest of the function here
    return (kf, Ek) if ret_eK else kf

So in this case if the ret_eK argument is specified and set to True, then kf, Ek is returned, otherwise just kf is returned. But in Python you really don't want to do this unless there is some major additional cost to calculating Ek, which doesn't appear to be in this case.

Upvotes: 2

Related Questions