如何通过改变参数对的数量来动态创建函数

时间:2017-07-20 21:28:02

标签: python function

所以我一直试图在运行时创建一个函数,它应该动态添加参数对。为了了解我正在寻找的东西,这是我到目前为止所做的:

def smart_func(terms):
    params = []
    for n in range(terms):
        params.append((2*n*np.pi, 2*n*np.pi))

    def func(t, freq, offset, *params):
        result = 0
        for (a,b) in zip(params):
            result += np.sin(a*freq*t) + np.cos(b*freq*t)
        return result
    return func

我知道这不起作用,但应该对我尝试做的事情有所了解。我已经看过这个question,但仍然无法找到解决方案。

为了给出更多解释,我需要将这个新创建的函数传递给这个

from scipy.optimize import curve_fit
    f_vars, f_cov = curve_fit(smart_func(terms=3), time_in_hours, full_fit_flux, p0=p0)

这将使我能够轻松确定适合我的数据所需的最少量参数。

这是我成功使用的硬编码功能。如果smart_func传递了3,它将返回此函数。

    def func(t, freq, offset, a0, b0, a1, b1, a2, b2):
        return b0 + a0 \
            + a1*np.sin(2.*np.pi*freq*t) \
            + b1*np.cos(2.*np.pi*freq*t) \
            + a2*np.sin(4*np.pi*freq*t) \
            + b2*np.cos(4*np.pi*freq*t) \
            + offset

如果smart_func传递了2

,那就是这样
    def func(t, freq, offset, a0, b0, a1, b1):
        return b0 + a0 \
            + a1*np.sin(2.*np.pi*freq*t) \
            + b1*np.cos(2.*np.pi*freq*t) \
            + offset

我想要的是根据指定的术语数量添加额外的a和b术语。

3 个答案:

答案 0 :(得分:1)

尝试:

def smart_func(terms):
        params = []
        for n in range(terms):
            params.append(2*n*np.pi)

        # def func(t, freq, offset, *args ) will
        # overwrites the original params list within func
        #

        def func(t, freq, offset, *args):
            an = []
            bn = []

            for i in range(len(args)):
                if i%2==0 :
                   an.append(args[i])
                else:
                   bn.append(args[i])
            result = 0

            pairs = zip(an,bn)

            for (q,ab) in zip(params, pairs):
                #q is 2 * n * pi  
                ai, bi = ab
                result += ai * np.sin(q*freq*t) + bi * np.cos(q*freq*t)
            return result
        return func

其中q是序列的项2 * i * pi for i in range(terms), 和对(ai,bi)是sin(q * freq * t)+ cos(q * freq * t)的系数。

答案 1 :(得分:1)

你想要的是部分功能。使用部分函数,​​您可以将特定的params值传递给func,它将返回一个具有常量param值的新函数。看看funcy图书馆。

from funcy import rpartial

def func(t, freq, offset, *params):
    result = 0
    for (a,b) in zip(params):
        result += np.sin(a*freq*t) + np.cos(b*freq*t)
    return result

params = (2 * np.pi, 2 * np.pi)
partial_func = rpartial(func, params)

#call partial_func like below
result = partial_func(t0, freq0, offset0)

答案 2 :(得分:1)

以下显示了如何动态创建所需的功能。请注意,我简化了动态函数的代码,以最大限度地减少冗余计算。

from textwrap import dedent

def test(num_terms):

    def smart_func(num_terms):  # nested to mimic OP's usage
        template = dedent('''
            def func(t, freq, offset, a0, b0, {params}):
                ang = 2.*np.pi*freq*t
                sin_ang = np.sin(ang)
                cos_ang = np.cos(ang)
                return (a0 + b0
            {terms}
                        + offset)
            ''')
        indent = ' ' * 12
        params, terms = [], []
        for i in range(1, num_terms):
            params.append('a{i}, b{i}'.format(i=i))
            terms.append((indent + '+ a{i}*sin_ang\n' +
                          indent + '+ b{i}*cos_ang').format(i=i))

        src_code = template.format(params=', '.join(params), terms='    \n'.join(terms))

        print('Dynamically created function of {} terms:'.format(num_terms))
        print(src_code)

        exec(src_code, globals(), locals())  # compile into function object
#        exec src_code in globals(), locals()  # older Python 2 syntax

        return locals()['func']  # return compiled function

    return smart_func(num_terms)  # return result of calling nested function

print(test(3))

输出:

Dynamically created function of 3 terms:

def func(t, freq, offset, a0, b0, a1, b1, a2, b2):
    ang = 2.*np.pi*freq*t
    sin_ang = np.sin(ang)
    cos_ang = np.cos(ang)
    return (a0 + b0
            + a1*sin_ang
            + b1*cos_ang
            + a2*sin_ang
            + b2*cos_ang
            + offset)

<function func at 0x0232A228>