使用异常处理、*args 和 **kwargs 删除函数的无穷大值

Posted

技术标签:

【中文标题】使用异常处理、*args 和 **kwargs 删除函数的无穷大值【英文标题】:Removing infinity values of a function using exception handling, *args, and **kwargs 【发布时间】:2015-08-17 22:09:13 【问题描述】:

我目前正在阅读 Joel Grus 的 Data Science from Scratch 一书,我遇到了一个我不太了解的函数:

def safe(f):
    def safe_f(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except:
            return float('inf')
    return safe_f

在梯度下降算法中调用安全函数以删除无穷大值。

def minimize_batch(target_fn, gradient_fn, theta_0, tolerance=0.000001):
    step_sizes = [100, 10, 1, 0.1, 0.001, 0.0001, 0.00001]

    theta = theta_0
    target_fn = safe(target_fn)
    value = target_fn(theta)

    while True:
        gradient = gradient_fn(theta)
        next_thetas = [step(theta, gradient, -step_size) for step_size in     step_sizes]
        next_theta = min(next_thetas, key=target_fn)
        next_value = target_fn(next_theta)

        if abs(value - next_value) < tolerance:
            return theta
        else:
            theta, value = next_theta, next_value

我了解安全功能的要点,但我不明白 如何 它是这样做的。例如,如果 target_fn 没有输入,如何安全评估 target_fn?什么是安全的,它知道如何删除无穷大值?

抛开梯度下降不谈,这个安全函数是否可以在无数个地方都未定义的疯狂函数上工作?

【问题讨论】:

对我来说,它看起来并没有删除无穷大值。看起来它是在添加无穷大值,而不是引发异常。例如,return 1 / x 的不安全版本在 x 为零时引发 ZeroDivisionError;安全装饰的版本不会引发异常,而是返回无穷大。 如果您知道safe 是一个装饰器 函数,并且f 可以在safe_f 中通过关闭. 【参考方案1】:

如果我们一步一步替换变量名,可能会帮助你理解:

target_fn = safe(target_fn)

表示safe中的ftarget_fn

def safe(target_fn):
    def safe_f(*args, **kwargs):
        try:
            return target_fn(*args, **kwargs)
        except:
            return float('inf')
    return safe_f

和:

target_fn = safe_f

即我们将最初绑定到target_fn 的函数替换为我们刚刚在装饰器函数 safe 中创建的函数safe_f,通过闭包保留对原始f 的访问权限

所以参数是通过*args, **kwargs 传递的(见What does ** (double star) and * (star) do for parameters?):

next_value = target_fn(next_theta)

解决为:

def safe_f(next_theta):
    try:
        return target_fn(next_theta)
    except:
        return float('inf')

即要么返回调用原始 target_fn 并带有参数 next_theta 的结果,或者,如果这样做时发生任何错误,则返回 float('inf')

这个safe 函数会在无数个地方都未定义的疯狂函数上工作吗?

由于它使用*args, **kwargs,您可以使用它来包装any 函数,它会悄悄地抑制函数引发的any 错误并返回float('inf') -不过,这并不总是可取的!装饰器函数还有许多其他用途,通常使用@decorator 语法应用(例如,用于classstatic 方法properties );参见例如What are some common uses for Python decorators?

【讨论】:

以上是关于使用异常处理、*args 和 **kwargs 删除函数的无穷大值的主要内容,如果未能解决你的问题,请参考以下文章

get_list_or_404(klass, *args, **kwargs)和get_object_or_404(klass, *args, **kwargs)区别

python中*args和**kwargs的使用

Python中*args和**kwargs 的简单使用

参数arg、*args、**kwargs三个的区别

*args和**kwargs

Python之*args和**kwargs使用方法