【问题标题】:Python: Making a list that includes functions but has as-yet undefined argumentsPython:制作一个包含函数但具有尚未定义的参数的列表
【发布时间】:2016-06-14 16:19:31
【问题描述】:

一般来说,我想做的是制作一个涉及一些函数或函数的列表,但是该函数的参数会根据 for 循环的“i”而改变,因此当参数没有完全定义时我定义列表。 想象一下 func(x),我想要一个类似 [func(x * i), func(x * i**2)] 的列表,例如。意思是,将定义一些参数 x,但我想通过“i”修改它,它是 for 循环中的迭代器。 具体来说,我想做的是从某种模式(由列表表示)中构建一个二维数组,该模式将以数组的对角线为中心。但是,模式的值会根据我所在的数组的行而变化。所以我跟踪我们在哪一行,并使用那个“i”值作为函数中的参数。 问题是,当我定义列表时,它会尝试评估函数,然后因为 i 尚未定义而崩溃(一旦我们通过 for 循环就会定义) 有什么方法可以延迟列表中函数的评估,直到它进入 for 循环?

【问题讨论】:

    标签: python arrays function numpy


    【解决方案1】:

    我怀疑对于您的二维数组,定义对角线的方法比遍历行和计算这样的函数更好。但要专注于“延迟”函数评估的问题,我会试试这个:

    定义一个简单的函数

    In [438]: def func(x):
       .....:     return x**2
       .....: 
    

    此列表定义不起作用,因为解释器在将x*i 传递给func 之前尝试评估它们。它将使用现有的 xi

    In [442]: [func(x*i),func(x*i**2)]
    ...
    
    NameError: name 'x' is not defined
    

    相反,我可以将每个函数调用包装在另一个函数调用中。它可能是一个命名函数,或者像我在这里所做的一个未命名的lambda。就像func 的主体一样,x*i 被延迟到调用 lambda:

    In [443]: [lambda x,i:func(x*i), lambda x,i: func(x*i**2)]
    Out[443]: [<function __main__.<lambda>>, <function __main__.<lambda>>]
    
    In [444]: flist=_   # assign that list to a new name for later use
    

    现在我们可以定义 xi 并评估列表中的函数:

    In [445]: x=np.arange(3)    
    In [446]: i=2
    In [447]: [f(x,i) for f in flist]
    Out[447]: [array([ 0,  4, 16]), array([ 0, 16, 64])]
    

    或者我们可以在 i 的迭代中包装它:

    In [449]: [[f(x,i) for f in flist] for i in range(3)]
    Out[449]: 
    [[array([0, 0, 0]), array([0, 0, 0])],
     [array([0, 1, 4]), array([0, 1, 4])],
     [array([ 0,  4, 16]), array([ 0, 16, 64])]]
    

    我什至可以将其变成 3d 数组:

    In [450]: np.array(_)
    Out[450]: 
    array([[[ 0,  0,  0],
            [ 0,  0,  0]],
    
           [[ 0,  1,  4],
            [ 0,  1,  4]],
    
           [[ 0,  4, 16],
            [ 0, 16, 64]]])
    

    另一种方法是参数化包装函数

    In [451]: def func1(x,i,p=1):
       .....:     return func(x*i**p)
    
    In [452]: [[func1(x,i,p) for p in [1,2]] for i in range(3)]
    Out[452]: 
    [[array([0, 0, 0]), array([0, 0, 0])],
     [array([0, 1, 4]), array([0, 1, 4])],
     [array([ 0,  4, 16]), array([ 0, 16, 64])]]
    

    functools 有一个 partial 函数,可以让我在延迟完整评估的同时指定函数的一些参数:

    partial(func, *args, **keywords) - 部分应用给定参数和关键字的新函数。

    In [461]: from functools import partial
    
    In [462]: flist=[partial(func1,p=1), partial(func1,p=2)]
    
    In [463]: [[f(x,i) for f in flist] for i in range(3)]
    Out[463]: 
    [[array([0, 0, 0]), array([0, 0, 0])],
     [array([0, 1, 4]), array([0, 1, 4])],
     [array([ 0,  4, 16]), array([ 0, 16, 64])]]
    

    事实上,如果我调整 func1,我可以同时分配 ip 部分:

    In [464]: def func1(x,i=0,p=1):
        return func(x*i**p)
    
    In [465]: flist=[partial(func1,p=1), partial(func1,p=2)]    
    In [466]: fflist=[[partial(f,i=i) for f in flist] for i in range(3)]
    
    In [467]: fflist
    Out[467]: 
    [[functools.partial(<function func1 at 0xb4d3e3d4>, i=0, p=1),
      functools.partial(<function func1 at 0xb4d3e3d4>, i=0, p=2)],
     [functools.partial(<function func1 at 0xb4d3e3d4>, i=1, p=1),
      functools.partial(<function func1 at 0xb4d3e3d4>, i=1, p=2)],
     [functools.partial(<function func1 at 0xb4d3e3d4>, i=2, p=1),
      functools.partial(<function func1 at 0xb4d3e3d4>, i=2, p=2)]]
    

    评估这个仍然需要遍历嵌套列表:

    In [471]: [[f(x) for f in ff] for ff in fflist]
    Out[471]: 
    [[array([0, 0, 0]), array([0, 0, 0])],
     [array([0, 1, 4]), array([0, 1, 4])],
     [array([ 0,  4, 16]), array([ 0, 16, 64])]]
    

    我可以通过一次调用 partial(对于每个“单元格”)来创建 fflist

    fflist=[[partial(func1,i=i,p=p) for p in [1,2]] for i in range(3)]
    

    可以通过将fflist 设为对象 dtype 数组来简化迭代,但这是后一个问题。

    还有其他包装函数以供以后评估的方法,但这些是最简单和最明显的。

    我也可以将partialx 参数一起使用

    In [478]: z=[[partial(f,x) for f in ff] for ff in fflist]
    
    In [479]: z
    Out[479]: 
    [[functools.partial(<function func1 at 0xb4d3e3d4>, array([0, 1, 2]), i=0, p=1),
      functools.partial(<function func1 at 0xb4d3e3d4>, array([0, 1, 2]), i=0, p=2)],
     ....]]
    
    In [480]: [[f() for f in ff] for ff in z]
    

    【讨论】:

    • 感谢您实际上回答了延迟评估的问题,而不是担心我想用它做什么以及如何避免在我的任务中使用这种方法。在 SE 上,人们经常尝试重写您的代码,而不是回答所提出的问题。
    【解决方案2】:

    在循环内定义列表:

    for i in whatever:
        l = [func(x * i), func(x * i**2)]
    

    鉴于您已标记此 NumPy,使用列表可能不是一个好主意,但我们无法从所问的问题中真正判断您应该做什么。

    【讨论】:

    • 我只是想到了这一点,但问题是列表(准确地说是 3 个)都是函数的参数。程序在尝试初始化参数时崩溃。
    • @MattF:要么你设计了这个函数错误,要么你试图使用错误。您必须更改设计的某些方面才能使其正常工作。真的很难说出你在描述什么,所以我不能说你必须改变哪一部分。
    • 我正在创建一个对角矩阵,其对角线是重复模式。因此,我正在遍历列表以将适当的项目放置在适当的列中。很可能有一个 NumPy 函数可以创建这样的对角矩阵,这就是我标记它的原因。如果有帮助,我可以发布代码,但如果有一种 Python 的方式来延迟评估,就像 Mathematica 所做的那样,那将是最简单的
    猜你喜欢
    • 2022-07-04
    • 1970-01-01
    • 1970-01-01
    • 2015-01-14
    • 2017-10-16
    • 2019-05-29
    • 2011-06-06
    • 2019-09-08
    • 2015-06-14
    相关资源
    最近更新 更多