[Tutor] constructing semi-arbitrary functions

Oscar Benjamin oscar.j.benjamin at gmail.com
Mon Feb 17 22:07:31 CET 2014


On 17 February 2014 20:13, Peter Otten <__peter__ at web.de> wrote:
> André Walker-Loud <walksloud at gmail.com> wrote:
>>
>> The 3rd party minimizer utilizes the .func_code.co_varnames and
>> .func_code.co_argcount to determine the name and number of variables to
>> minimize.  eg.
>>
>> =========
>> METHOD 2: use strings, exec and globals to construct function
>> def minimize(pars,x,y,dy):
>>     global g_x, g_y, g_dy
>>     g_x = x; g_y = y; g_dy = dy
>>     argnames = ['c_%i'%(i) for i in range(len(pars))]
>>     funcargs = ", ".join(argnames)
>>     funcdef = 'def chisq_mn(' + funcargs + '):\n'
>>     funcdef += '    global g_x, g_y, g_dy\n'
>>     funcdef += '    return chisq(['+funcargs+'],g_x,g_y,g_dy)\n' #chisq is
>>     defined in same file
>>     # evaluate string and build function
>>     print "funcdef=", funcdef
>>     exec funcdef in globals()
>
> I think you are looking for closures:

Closures would be a good fit for this if the third-party minimisation
routine didn't assume that it always receives a function whose formal
parameters are the variables to be minimised and have the names that
are intended for display.

This one would work (assuming that we want to minimise over x):

> def make_poly(coeff):
>     def poly(x):
>         return sum(c * x ** n for n, c in enumerate(coeff))
>     return poly

This one won't work:

> def minimize(x, y, dy):
>     def chisq_mn(*args):
>         return chisq(args, x, y, dy)
>     return chisq_mn

>>> def minimize(x, y, dy):
...     def chisq_mn(*args):
...         return chisq(args, x, y, dy)
...     return chisq_mn
...
>>> f = minimize(2, 4, 0.1)
>>> f.func_code.co_varnames
('args',)
>>> f.func_code.co_argcount
0

The OP wants to pass this function to a routine that looks like:

def minimise(func):
    num = func.func_code.co_argcount
    names = func.func_code.co_varnames
    # Actual minimisation code
    return _minimise(func, num, names)

If it's as simple as above then it may be straightforward to just
import the underlying _minimise routine and rewrite the minimise
function so that it looks like:

def minimise(func, parameter_names=None):
    if parameter_names is not None:
        num = func.func_code.co_argcount
        names = func.func_code.co_varnames
    else:
        num = len(parameter_names)
    # Actual minimisation code
    return _minimise(func, num, names)


Oscar


More information about the Tutor mailing list