使用 setattr() 将字符串转换为变量

Using setattr() to convert strings to variables

我正在创建一个 sigsum() 函数,它使用输入方程和输入变量求和。这是我目前所拥有的:

def sigsum(eqn, index, lower=0, upper=None, step=1):

    if type(step) is not int:
        raise TypeError('step must be an integer')
    elif step < 1:
        raise ValueError('step must be greater than or equal to 1')

    if upper is None:
        upper = 1280000

    if lower is None:
        lower = -1280000

    if (upper - lower) % step:
        upper -= (upper - lower) % step

    index = lower
    total = 0
    while True:
        total += eqn
        if index == upper:
            break
        index += step

    return total

函数的使用:

print(sigsum('1/(i+5)','i'))
>>> 12.5563

我当前的问题是将 'eqn' 和 'index' 转换为存在于函数局部命名空间内的变量。我听说使用 exec 不是一个好主意,也许 setattr() 可能会起作用。谁能帮我吗? 谢谢

对于 eqn 我建议使用 lambda 函数:

eqn = lambda i: 1 / (i + 5)

那么不需要index,因为它只是"the variable passed to the function"(不需要名字)。

那么你的函数就变成了

def integrate(fn, start = 0, end = 128000, step = 1):
    """
    Return a stepwise approximation of
      the integral of fn from start to end
    """
    num_steps = (end - start) // step
    if num_steps < 0:
        raise ValueError("bad step value")
    else:
        return sum(fn(start + k*step) for k in range(num_steps))

你可以运行喜欢

res = step_integrate(eqn)   # => 10.253703030104417

请注意,这有很多步骤,其中许多涉及非常小的数字;舍入误差可能成为一个主要问题。如果精度很重要,您可能需要手动推导积分,

from math import log

eqn          = lambda i: 1 / (i + 5)
eqn.integral = lambda i: log(i + 5)

def integrate(fn, start = 0, end = 128000, step = 1):
    """
    Return the integral of fn from start to end

    If fn.integral is defined, used it;
    otherwise do a stepwise approximation
    """
    if hasattr(fn, "integral"):
        return fn.integral(end) - fn.integral(start)
    else:
        num_steps = (end - start) // step
        if num_steps < 0:
            raise ValueError("bad step value")
        else:
            return sum(fn(start + k*step) for k in range(num_steps))

这又是运行像

res = step_integrate(eqn)   # => 10.150386692204735

(请注意,逐步逼近大约高出 1%。)

我会按照 Hugh Bothwell 的建议使用 lambda 函数 将不得不修改 sigsum 如下

def sigsum(eqn, lower=0, upper=None, step=1):

    if type(step) is not int:
        raise TypeError('step must be an integer')
    elif step < 1:
        raise ValueError('step must be greater than or equal to 1')

    if upper is None:
        upper = 1280000

    if lower is None:
        lower = -1280000

    if (upper - lower) % step:
        upper -= (upper - lower) % step

    index = lower
    total = 0
    while True:
        total += eqn(index)
        if index == upper:
            break
        index += step

    return total

函数的使用:

print(sigsum(lambda i: 1/(i+5)))
>>> 12.5563

你也可以单独定义一个函数:

def myfunction(i):
     return 1/(i+5)

并将其传递给 sigsum

print(sigsum(myfunction))
>>> 12.5563

能够将函数作为参数传递在计算机语言语音函数中作为第一个 class 对象调用。 (例如 C 和 java 没有,javascript 和 python 有)