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

Python 如何通过改变参数对的数量动态创建函数,python,function,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)

因此,我一直在尝试在运行时创建一个函数,它应该动态地添加成对的参数。为了让大家了解我在寻找什么,以下是我迄今为止所做的:

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
我知道这不起作用,但应该让我知道我在尝试做什么。我已经研究过这个问题,但仍然无法找到解决方案

为了进一步解释,我需要将这个新创建的函数传递到

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术语。

试试:

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是范围内i的序列2*i*pi的项(项), 和对(ai,bi)是sin(q*freq*t)+cos(q*freq*t)的系数。

试试:

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是范围内i的序列2*i*pi的项(项),
和对(ai,bi)是sin(q*freq*t)+cos(q*freq*t)的系数。

你想要的是一个偏函数。使用分部函数,可以将特定的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)

你想要的是一个部分函数。使用分部函数,可以将特定的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)

下面显示了如何动态创建所需的函数。请注意,我简化了动态函数的代码以最小化冗余计算

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))
输出:

动态创建3个术语的函数:
def func(t、频率、偏移量、a0、b0、a1、b1、a2、b2):
ang=2.*np.pi*freq*t
sin_ang=np.sin(ang)
cos_ang=np.cos(ang)
返回(a0+b0
+a1*Sinu ang
+b1*cos_ang
+a2*Sinu ang
+b2*cos_ang
+偏移量)

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

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))
输出:

动态创建3个术语的函数:
def func(t、频率、偏移量、a0、b0、a1、b1、a2、b2):
ang=2.*np.pi*freq*t
sin_ang=np.sin(ang)
cos_ang=np.cos(ang)
返回(a0+b0
+a1*Sinu ang
+b1*cos_ang
+a2*Sinu ang
+b2*cos_ang
+偏移量)


我不明白,为什么要在运行时这样做?为什么不定义一个包含t、freq和offset的函数呢?我不清楚你想要什么
params
是一个数字列表,AFAIKT
def my_function(*params):
定义函数以获取任意数量的参数,这些参数将被收集到名为
params
的单个值序列中,然后可以像任何其他可变长度容器一样处理这些值。您的
def func
在末尾已经有了它,所以不清楚您在问什么。因为我将这个新创建的函数赋予另一个曲线拟合,一个拟合函数。我需要在函数中定义所有参数。你关心这些参数的名称吗?我不明白,你为什么要在运行时这样做?为什么不定义一个包含t、freq和offset的函数呢?我不清楚你想要什么
params
是一个数字列表,AFAIKT
def my_function(*params):
定义函数以获取任意数量的参数,这些参数将被收集到名为
params
的单个值序列中,然后可以像任何其他可变长度容器一样处理这些值。您的
def func
在末尾已经有了它,所以不清楚您在问什么。因为我将这个新创建的函数赋予另一个曲线拟合,一个拟合函数。我需要在函数中定义所有参数。您关心这些参数的名称吗?对于第一次运行,I%0抛出一个除以零的错误,我是指I%2,而不是I%0。这很接近。但是,args*包含t、freq、offset,然后是另外5个args。因此t、freq和offset位于*args之前,因此它们不会相互影响。对于5个参数,我计算了3-t、freq和offset。其他2是什么?实际上我只是在没有猜测参数的情况下运行了它,并注意到它是完全空的。curve_fit看到的参数不存在。对于第一次运行i%0抛出一个除以零的错误ry,我的意思是i%2,而不是i%0。这很接近。但是,args*包含t、freq、offset,然后是另外5个args。因此t、freq和offset位于*args之前,因此它们不会相互影响。对于5个参数,我计算了3-t、freq和offset。其他2是什么?实际上我只是在没有猜测参数的情况下运行了它,并注意到它是完全空的。curve_fit看到的参数不存在。嗯,我得到一个错误SyntaxError:函数“smart_func”中不允许使用非限定exec,因为它是一个嵌套函数。我在前面尝试使用execIt时遇到了这个问题,这是一个Python版本的问题,我使用的是3.6.2,您必须使用2.x。请尝试使用exec(函数、全局函数()、局部函数()),如果不起作用,请尝试在全局函数()、局部函数()中使用exec函数()。谢谢!通过一些调整,我让它完全达到了我所期望的效果,与硬编码函数给我的结果完全一致。乔瓦尼:很高兴听到这个消息。注意我做了一些相对较小的更改,主要是为了提高代码的可读性。嗯,我得到一个错误SyntaxError:函数“smart_func”中不允许使用非限定exec,因为它是一个嵌套函数。我之前在尝试使用execIt时遇到了这个问题,这是Python版本的问题,我很抱歉