在被覆盖的forloop中创建的lambda函数

2024-10-01 04:56:05 发布

您现在位置:Python中文网/ 问答频道 /正文

执行以下代码

# horizontals : list of functions
#     A list of spline functions
# vertical : function
#     Line function
# 
# All are given in the form f(x) = y

def mwe(horizontals, vertical):
    tangents = []
    for spline in horizontals:  
        x0, b = intersection(spline, vertical)  # Returns (float, float)

        m = float(spline(x, 1))
        tangent = lambda x: m * (x - x0) + b

        tangents.append(tangent)

        print(tangent(0))
        print(tangents[-1](0))


    print()
    for tangent in tangents:
        print(tangent(0))

此输出中的结果:

715.2170619670379
715.2170619670379
851.5168419777629
851.5168419777629
992.2507908527389
992.2507908527389

992.2507908527389
992.2507908527389
992.2507908527389

我不明白为什么列表中的所有函数都被覆盖了?表达式中只有基元数据类型(浮动)不应该导致任何引用问题,是吗

编辑:如果有必要,代码将使用numpy/scipy作为样条线


Tags: of代码inforfunctiontangentfloatfunctions
3条回答

有什么问题

您可以从official python documentation中读取它,但简而言之

  • For循环不生成新的变量范围
  • lamba中的变量指向mwe()的范围,只有在调用lambda时才读取该值
<>考虑这个

x = 5
def myfunc():
    print(x)
mylambda = lambda : print(x)

x = 99
myfunc()
mylambda()

您认为控制台将打印什么内容?99,对吗(是的,两种情况下都是99)。请注意lambda的行为方式与常规函数完全相同;如果未在函数作用域中定义变量,python将从父作用域中搜索该变量。注意,在像这样的for循环之后

for x in range(5)
    pass
print(x)

x的值将为5。这就是为什么您创建的所有函数都具有相同的值(最后一个)的原因

那么,如何解决这个问题呢

很抱歉没有将示例代码复制粘贴到我的示例中。我正在用手机写答案,所以写简单的例子就容易多了。我希望你能从这些例子中得到答案

有三种方法可以解决这个问题

一,。使用lamba的局部变量

也就是说,而不是

a, b = 5, 8
func = lambda x: (x + a)/b

使用

a, b = 5, 8
func = lambda x, a0=a, b0=b: (x + a0)/b0

为清晰起见,lambda的局部变量附加了零(将使用相同的变量名)。请注意,这与

a, b = 5, 8
def func(x, a0=a, b0=b): 
    return (x + a0)/b0

在for循环中使用def func()语法也是一个不错的选择

二,。使用高阶函数

我的意思是,因为函数在python中是对象(或:first-class citizens),所以可以创建一个返回函数的函数。将函数作为参数或返回函数的函数称为高阶函数。您可以使用此选项创建更高阶的函数:

def get_func(a,b):
    return lambda x: (x+a)/b

或者,为什么不呢

def get_func(a,b):
    def inner(x):
        return (x+a)/b
    return inner

之后,只需在循环中使用

for i in range(5):
    a, b = get_params() # your logic here
    func = get_func(a,b)

这将起作用,因为get_func有自己的作用域

三,。使用partial()

内置functools有一个很棒的助手函数,名为partial,它也可以做您想要的事情

from functools import partial

def base_func(x, a, b):
    return (x-a)/b

funcs = []
for i in range(5):
    a, b = get_params() # your logic here
    func = partial(base_func, a=a, b=b)
    funcs.append(func)

您的lambda依赖于封闭作用域中的mx0b的定义,但是当lambda执行时,而不是在定义时,将加载该依赖项。因此,您在所有lambda中使用的是来自最终循环的值。您需要在定义时存储这些值。最简单的方法是使它们成为lambda的默认参数(参数默认值在定义时绑定):

    tangent = lambda x, m=m, x0=x0, b=b: m * (x - x0) + b

所以,我想我找到了一个方法让它发挥作用

# horizontals : list of functions
#     A list of spline functions
# vertical : function
#     Line function
# 
# All are given in the form f(x) = y

def mwe(horizontals, vertical):
    tangents = []
    for spline in horizontals:  
        x0, b = intersection(spline, vertical)  # Returns (float, float)

        m = float(spline(x, 1))
        exec("tangent = lambda x: {m} * (x - {x0}) + {b}".format(m=m,x0=x0,b=b))

        tangents.append(tangent)

        print(tangent(0))
        print(tangents[-1](0))


    print()
    for tangent in tangents:
        print(tangent(0))

exec在这里名声不好,但这是可行的,我想不出其他办法

相关问题 更多 >