Optimal multiple return values in scientific python

ipython, numpy, python, scipy

Solution

You could specify that you want more info returned using an `info=True` argument when calling `calculation`. This is the approach taken by np.unique (with its `return_inverse` and `return_index` parameters) and scipy.optimize.leastsq (with its `full_output` parameter):

def calculation(data, max_it=10000, tol = 1e-5, info=False):
    k = 0
    rmse = np.inf 
    while k < max_it and rmse > tol:
        #calc and modify data - rmse becomes smaller in each iteration
        k += 1
    if info:
        return data, k, rmse
    else:
        return data

Or, you could assign additional attributes on the `calculation` function:

def calculation(data, max_it=10000, tol = 1e-5):
    k = 0
    rmse = np.inf 
    while k < max_it and rmse > tol:
        #calc and modify data - rmse becomes smaller in each iteration
        k += 1
    calculation.k = k
    calculation.rmse = rmse
    return data

The added info would then be accessible with

import module
d = module.calculation(data)
rmse = module.calculation.rmse

Note that this latter approach will not work well if `calculation` is run concurrently from multiple threads...

In CPython (due to the GIL), only one thread can execute at any given time, so there is little attraction to running `calculation` in multiple threads. But who knows? there may be some situation which calls for some use of threads on a small scale, such as perhaps in a GUI. There, accessing `calculation.k` or `calculation.rmse` might return incorrect values.

Moreover, the Zen of Python says, "Explicit is better than implicit".

So I would recommend the first approach over the second.

Problem

I'm using scipy/numpy for research code instead of matlab. There is one flaw, I was running into frequently. I found a work-around solution, but want to check for a best practice and better solution. Imagine some mathematical optimisation: ``` def calculation (data, max_it=10000, tol = 1e-5): k = 0 rmse = np.inf while k < max_it and rmse > tol: #calc and modify data - rmse becomes smaller in each iteration k += 1 return data ``` It works fine, I embed it into my code, in multiple locations, e.g.: ``` import module d = module.calculation (data) ``` But sometimes I want to check further insights and need multiple return values. If I simply append multiple return values, I have to modify the other code and unpack the first return value. This is one of the few situations were I prefer matlab to scipy.In matlab only the first return value is evaluated, unless you explicitly demand the rest. So my work-around for matlab-like (= optimal) multiple return values are global variables [of the module] ``` def calculation (data, max_it=10000, tol = 1e-5): global k global rmse k = 0 rmse = np.inf while k < max_it and rmse > tol: #calc and modify data - rmse becomes smaller in each iteration k += 1 return data ``` My function calls work without modification and if I want to verify something in ipython, Iset some variables global reload(module) and check the insight with module.rmse. But I could also imagine a OO-aproach from the beginning, or to use pdb, or to use other ipython magic

Original source