You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Lambda函数使用copy/deepcopy无效?分段多项式调用报错排查

复用coeffs变量导致分段多项式函数维度不匹配错误

触发错误的最小代码示例

import numpy as np
from copy import deepcopy

x = np.array([0.       , 2.0943951, 4.1887902])

coeffs = np.array([[-0.08952269,  1.59581565, -0.55240446],
                    [ 2.33359441, -0.71809073,  0.        ]])

quadratic_spline = piecewise_polynomial(coeffs, x)
print(quadratic_spline(3))

coeffs = np.array([[ 0.06200785,  0.60701535, -0.        , -0.06631379],
                   [-1.15644773,  2.3523244 , -0.83332369,  0.06631379]])

print(quadratic_spline(3))

错误输出

0.17932221999999998

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/var/lib/condor/execute/dir_1389034/ipykernel_1403467/1828880745.py in <module>
     10                    [-1.15644773,  2.3523244 , -0.83332369,  0.06631379]])
     11 
---> 12 print(quadratic_spline(3))

<string> in <lambda>(x, order, xs)

ValueError: operands could not be broadcast together with shapes (3,) (4,) 

分段多项式函数定义

def piecewise_polynomial(coeffs, xs):
    """
    给定单变量分段多项式的系数和每段的区间边界,构造对应的函数。
    多项式的基函数为 1, x, x², ..., xⁿ, ...
    如果xs的长度过高,解析器无法处理复杂语法,函数会失效。
    
    输入:
    coeffs:np.2darray 
    xs:np.array
    
    返回:
    piecewise_polynomial:function float to float
    """
    coeffs = deepcopy(coeffs)
    function_str = f'lambda x, order={coeffs.shape[1]}, xs=np.{repr(xs)}: np.sum(np.array([x**n for n in range(order)])*coeffs[0]) if xs[0] <= x <= xs[1]'
    for i, x in enumerate(xs[1:-1], start=1):
        function_str += f' else (np.sum(np.array([x**n for n in range(order)])*coeffs[{i}]) if xs[{i}] < x <= xs[{i+1}]'
    
    function_str += f" else None{')'*(len(xs)-2)}"
    return eval(function_str)

已尝试的解决方法

  • quadratic_spline = piecewise_polynomial(coeffs.copy(), x)
  • quadratic_spline = piecewise_polynomial(copy.deepcopy(coeffs), x)
  • quadratic_spline = copy.deepcopy(piecewise_polynomial(coeffs, x))

以上方法及组合均未解决问题,只有不复用coeffs变量名才能避免错误。期望两次输出0.17932221999999998。


错误原因

问题核心在于eval生成的lambda函数并未固化创建时的coeffs值。虽然函数内执行了coeffs = deepcopy(coeffs),但生成的lambda字符串中直接引用了全局的coeffs变量,而非当时的副本值。当后续全局coeffs被重新赋值为4列数组后,lambda调用时仍使用原来的order=3(来自第一次创建时的coeffs.shape[1]),导致基函数数组形状(3,)与新coeffs的(4,)无法广播相乘,触发维度不匹配错误。

解决方案

方案1:将coeffs值嵌入lambda字符串

修改函数,把coeffs的具体值通过repr嵌入到lambda定义中,让lambda内部使用创建时的coeffs副本,而非全局变量:

def piecewise_polynomial(coeffs, xs):
    coeffs = deepcopy(coeffs)
    coeffs_repr = repr(coeffs)
    function_str = f'lambda x, order={coeffs.shape[1]}, xs=np.{repr(xs)}, coeffs=np.{coeffs_repr}: np.sum(np.array([x**n for n in range(order)])*coeffs[0]) if xs[0] <= x <= xs[1]'
    for i, x_val in enumerate(xs[1:-1], start=1):
        function_str += f' else (np.sum(np.array([x**n for n in range(order)])*coeffs[{i}]) if xs[{i}] < x <= xs[{i+1}]'
    
    function_str += f" else None{')'*(len(xs)-2)}"
    return eval(function_str)

方案2:改用闭包替代eval(推荐)

完全避免使用eval,用闭包封装状态,更安全可靠:

def piecewise_polynomial(coeffs, xs):
    coeffs = deepcopy(coeffs)
    xs = deepcopy(xs)
    order = coeffs.shape[1]
    
    def spline_func(x):
        # 查找x所在的区间索引
        idx = np.searchsorted(xs, x, side='right') - 1
        idx = np.clip(idx, 0, len(coeffs)-1)
        # 计算多项式值
        basis = np.array([x**n for n in range(order)])
        return np.sum(basis * coeffs[idx])
    
    return spline_func

闭包会保留函数创建时的coeffs、xs和order副本,后续修改全局变量不会影响内部引用,彻底解决问题。


内容的提问来源于stack exchange,提问作者Yodo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 10:17:59