Search code examples
pythonfunctionscipypartial

Python function vs partial - Scipy doesn't like partials


So I was reading the curve_fit documentation. curve_fit takes the function to be fitted as its first argument. I slightly modified the example code in order to give it a partial as the first argument:

In:

import numpy as np
from scipy.optimize import curve_fit
def func( t, x , a, b, c): # I added a dummy variable t so that I can apply partials later
    return a*np.exp(-b*x) + c + t 
func = partial( func, 0 ) # use of partial to remove the dummy variable
x = np.linspace(0,4,50)
y = func(x, 2.5, 1.3, 0.5)
yn = y + 0.2*np.random.normal(size=len(x))
popt, pcov = curve_fit(func, x, yn) # curve_fit gets a partial instead of a Python function

Out:
TypeError: <functools.partial object at 0x104551c58> is not a Python function

Ah, that's disappointing. I guess I will use a lambda next time. Anyway, what is the problem here? What is it that a function can do and that a partial cannot do?


Solution

  • curve_fit uses getargspec from the standard library inspect to determine the arguments to the function. Unfortunately, getargspec doesn't handle a partial:

    In [31]: from inspect import getargspec
    
    In [32]: from functools import partial
    
    In [33]: def func(t, x, a, b, c):
       ....:     return a*np.exp(-b*x) + c + t
       ....: 
    
    In [34]: pfunc = partial(func, 0)
    

    getargspec(func) works fine.

    In [35]: getargspec(func)
    Out[35]: ArgSpec(args=['t', 'x', 'a', 'b', 'c'], varargs=None, keywords=None, defaults=None)
    

    But getargspec doesn't handle a partial function:

    In [36]: getargspec(pfunc)
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-36-3fb5eaea7c94> in <module>()
    ----> 1 getargspec(pfunc)
    
    /Users/warren/anaconda/python.app/Contents/lib/python2.7/inspect.pyc in getargspec(func)
        814         func = func.im_func
        815     if not isfunction(func):
    --> 816         raise TypeError('{!r} is not a Python function'.format(func))
        817     args, varargs, varkw = getargs(func.func_code)
        818     return ArgSpec(args, varargs, varkw, func.func_defaults)
    
    TypeError: <functools.partial object at 0x107ec6d08> is not a Python function