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

Scipy中_NQuad的integrate函数为何无需赋值即可更新args?

技术问询

请问为何在Scipy的_NQuad类的integrate函数中,args参数未经过显式赋值操作却能被更新?请结合以下代码进行解释:

from scipy.integrate import quad
from functools import partial

class _RangeFunc:
    def __init__(self, range_):
        self.range_ = range_

    def __call__(self, *args):
        """Return stored value.

        *args needed because range_ can be float or func, and is called with
        variable number of parameters.
        """
        return self.range_

class _OptFunc:
    def __init__(self, opt):
        self.opt = opt

    def __call__(self, *args):
        """Return stored dict."""
        return self.opt


class _NQuad:
    
    def __init__(self, func, ranges, opts, full_output):
        self.loop = 0
        self.abserr = 0
        self.func = func
        self.ranges = ranges
        self.opts = opts
        self.maxdepth = len(ranges)
        self.full_output = full_output
        if self.full_output:
            self.out_dict = {'neval': 0}

    def integrate(self, *args, **kwargs):
        depth = kwargs.pop('depth', 0)
        if kwargs:
            raise ValueError('unexpected kwargs')

        # Get the integration range and options for this depth.
        ind = -(depth + 1)
        fn_range = self.ranges[ind]
        low, high = fn_range(*args)
        fn_opt = self.opts[ind]
        opt = dict(fn_opt(*args))

        if 'points' in opt:
            opt['points'] = [x for x in opt['points'] if low <= x <= high]
        if depth + 1 == self.maxdepth:
            f = self.func
        else:
            f = partial(self.integrate, depth=depth+1)
        quad_r = quad(f, low, high, args=args, full_output=self.full_output,**opt)
        print(f'loop: {self.loop}; args: {args}; quad_r: {quad_r}')
        self.loop += 1
        value = quad_r[0]
        abserr = quad_r[1]
        if self.full_output:
            infodict = quad_r[2]
            # The 'neval' parameter in full_output returns the total
            # number of times the integrand function was evaluated.
            # Therefore, only the innermost integration loop counts.
            if depth + 1 == self.maxdepth:
                self.out_dict['neval'] += infodict['neval']
        self.abserr = max(self.abserr, abserr)
        if depth > 0:
            return value
        else:
            # Final result of N-D integration with error
            if self.full_output:
                return value, self.abserr, self.out_dict
            else:
                return value, self.abserr


def nquad(func, ranges, args=None, opts=None, full_output=False):

    depth = len(ranges)
    ranges = [rng if callable(rng) else _RangeFunc(rng) for rng in ranges]
    if args is None:
        args = ()
    if opts is None:
        opts = [dict([])] * depth

    if isinstance(opts, dict):
        opts = [_OptFunc(opts)] * depth
    else:
        opts = [opt if callable(opt) else _OptFunc(opt) for opt in opts]
    return _NQuad(func, ranges, opts, full_output).integrate(*args)


def func(x, y):
    return x*y**2

ranges = [[0, 2], [0, 1]]
opts = {"epsabs": 1.49e-8, "epsrel": 1.49e-8}
args = ()
full_output = False

result = nquad(func=func, ranges=ranges, args=args, opts=opts, full_output=False)
result
原理解析

_NQuad类的integrate方法中,args是可变长度参数元组,会被传递给quad函数的args参数,核心逻辑在于quad的工作机制:

  • 当积分深度未达最大值时,代码会通过partial创建绑定了depth=depth+1的integrate方法,作为当前quad调用的被积函数
  • quad执行单变量积分时,会将当前遍历到的积分变量值追加到传入的args元组末尾,再调用被积函数(即下一层的integrate)
  • 由于每次调用下一层integrate时,传入的是新的args元组(原args+当前积分变量),从外层视角看,就像是args被"隐式更新"了

需要明确:Python的元组是不可变类型,不存在真正的"更新"操作——每一层的args都是独立的新元组,只是内容包含了上层参数加上当前积分变量,以此实现多变量积分时参数的逐层传递。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 18:24:54