在另一个函数内部和外部定义函数之间的区别

Difference between defining a function inside versus outside of another function

我写了一个函数 derivative(w1, w2, pt) 来计算函数 f(x) = w1 * x**3 + w2 * x - 1 在点 pt 的导数。奇怪的是,我发现根据 def f(x) 位于 derivative(w1, w2, pt) 内部还是外部,我会得到不同的结果。为什么 def f(x) 的定位很重要/哪个是正确的?

示例 1:

def derivative(w1, w2, pt):
    x = sy.Symbol('x')

    def f(x):
        return w1 * x**3 + w2 * x - 1

    # Get derivative of f(x)
    def df(x):
        return sy.diff(f(x),x)

    # Evaluate at point x
    return df(x).subs(x,pt)   

来自derivative(5, 8, 2) returns 68.

示例 2:

def f(x):
    return w1 * x**3 + w2 * x - 1

def derivative(w1, w2, pt):
    x = sy.Symbol('x')

    # Get derivative of f(x)
    def df(x):
        return sy.diff(f(x),x)

    # Evaluate at point x
    return df(x).subs(x,pt)

来自derivative(5, 8, 2) returns 53.

我认为是你的全局范围被污染了。看看这个例子:

import sympy as sy

def f(x, w1, w2):
    return w1 * x**3 + w2 * x - 1

def derivative(w1, w2, pt):
    x = sy.Symbol('x')

    # Get derivative of f(x)
    def df(x, w1, w2):
        return sy.diff(f(x, w1, w2),x)

    # Evaluate at point x
    return df(x, w1, w2).subs(x,pt)

print(derivative(5, 8, 2))

这只是示例 2 的修改版本,returns 答案相同。

嵌套函数可以访问父函数中的局部名称。当您定义 f outside 时,它无法访问本地 w1w2,因此它必须假设它们是 globals 代替。

如果你没有在全局级别定义 w1w2,你的第二个版本实际上会引发 NameError:

>>> import sympy as sy
>>> def f(x):
...     return w1 * x**3 + w2 * x - 1
...
>>> def derivative(w1, w2, pt):
...     x = sy.Symbol('x')
...     def df(x):
...         return sy.diff(f(x),x)
...     return df(x).subs(x,pt)
...
>>> derivative(5, 8, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in derivative
  File "<stdin>", line 4, in df
  File "<stdin>", line 2, in f
NameError: name 'w1' is not defined

你没有得到异常意味着你之前已经定义了w1w2,并且是那些值 正被用来提供您的错误答案。

您可以 'fix' 您的第二个示例,方法是将 w1w2 设置为全局变量。作为第一个和第二个参数传递给 derivative() 调用实际上并不重要,因为那些 w1w2 参数值被 完全忽略:

>>> w1 = 5
>>> w2 = 8
>>> derivative('This value is ignored', 'And so is this one', 2)
68

在您的本地设置中,您 可能w1w2 分别设置为 45,因为x53:

的值
>>> w1 = 4
>>> w2 = 5
>>> derivative('This value is ignored', 'And so is this one', 2)
53

对于你的第一个例子,w1w2是由derivative()当地人提供的;无论您定义了什么全局名称,都不会使用这些名称。

如果你想在derivative()之外定义f,仍然先把w1w2传给derivative(),那么你还需要将这些相同的值传递给 f() 函数:

def f(x, w1, w2):
    return w1 * x**3 + w2 * x - 1

def derivative(w1, w2, pt):
    x = sy.Symbol('x')

    # Get derivative of f(x, w1, w2)
    def df(x):
        return sy.diff(f(x, w1, w2), x)

    # Evaluate at point x
    return df(x).subs(x,pt)

现在 f() 明确地从嵌套的 df() 函数接收 w1w2,而不是从全局函数接收。