【问题标题】:Call functions in Python Nested List在 Python 嵌套列表中调用函数
【发布时间】:2021-08-19 06:22:54
【问题描述】:

我需要遍历 python 中的嵌套列表,其中列表项是函数调用(列表中的第一项是函数,其余项是该函数的参数)。 这些参数本身也可以是带参数的函数,因此是嵌套的。一个列表也可以包含一个没有参数的函数。 像这样: ['foo','arg1','arg2'] 要么: [['foo','arg1','arg2'],['bar'],['baz','arg1']] 要么: ['foo','arg1',['baz','arg1']] 等等。

这是一个使用虚构 sum 和 product 函数的示例... Sum 相加,Product 相乘;如果我们评估函数,我们会得到 10。

['sum',['product',2,3],4]

我可以将函数和参数传递给另一个函数,该函数对我的安全函数进行实际“调用”,但实际上递归迭代列表时遇到了麻烦。 这是一个悲伤的尝试:

def process_list(l):
        if isinstance(l,list):
            results = []
            for item in l:
                if isinstance(item,list):
                    func = item[0]
                    args = item[1:]
                    for idx, arg in enumerate(args):
                        if isinstance(arg,list):
                            args[idx] = process_list(arg)
                    results.append(function_caller_result(func,args)) #what if that's a list?
                else:
                    results.append(item)
            return results
        return l


这里的任何帮助将不胜感激!提前致谢! :)

【问题讨论】:

  • [['foo','arg1','arg2'],['bar'],['baz','arg1']] 输出会是什么? foo 会返回(假设)1bar 会返回2baz 会返回3,所以你会期望[1, 2, 3]?第二个和第三个参数现在没有可以传递给它们的函数,在任何情况下,如果列表或嵌套列表中的第一个元素不是函数,它将导致像我解释的那样的情况,希望我说清楚了,例如:[['foo', 1, 2], [['foo' ,1, 2], 1, 2], [['foo' ,1, 2], 1, 2]]

标签: python recursion nested-loops nested-lists


【解决方案1】:

您正在尝试构建一种递归函数,但需要手动构建。如果嵌套大于您编码的内容,那将不起作用。

改为编写递归函数:

my_list = ['sum',['product',2,3],4]

def process(l):
    l = l.copy()
    for item in l:
        if isinstance(item,list):
            l.replace(item, process(item))
    return function_caller_result(*l) 
    # suppose l = [1, [2], '3']
    # func(*l) => func(1, [2], '3')

result = process(my_list)

【讨论】:

    【解决方案2】:

    你可以使用递归解包:

    eval_d = {'sum':lambda x, y:x+y, 'product':lambda x, y:x*y} #dict to store function names with an associated callable
    data = [['sum',['product',2,3],4]]
    def eval_f(d):
       r = [eval_d[a](*[i if not isinstance(i, list) else eval_f([i]) for i in b]) 
            for a, *b in d]
       #r now stores the result from the function calls
       return sum(r) #for this example to work, a cumulate sum is returned, but you can also just return the list
    
    print(eval_f(data))
    

    输出:

    10
    

    此解决方案的目标是在向 eval_f 传递具有函数签名的列表列表(即 [['foo','arg1','arg2'],['bar'],['baz','arg1']])的情况下工作。因此,必须将单个函数调用包装在一个列表中以确保该模式成立:['foo','arg1','arg2'] 将传递给 eval_f[['foo','arg1','arg2']]

    【讨论】:

    • 你的解释让我意识到我的解决方案中也存在一些错误,所以谢谢你,我有一个问题,[['sum', 1, 2], ['sum', 1, 2], ['sum', 1, 2]] 你的解决方案给出了9,但是如何决定@ 987654330@所有中间结果? [3, 3, 3]?这就是最后一条评论所解释的吗?英语不是我的主要语言,所以我可能解释错了
    • @python_user 我只包含了最终的求和 return sum(r) 以便函数 eval_f 会产生合理的结果。根据 OP 的代码,r 本身可能应该在实践中返回,但由于我们没有 foobarbaz 的实现,因此提供一个解决方案更有意义基本表达式评估,采用 OP 整体输入的风格。
    【解决方案3】:

    你可以试试这个递归函数,它适用于 Ajax1234 解决方案失败的一些测试。

    我注意到他们的输入格式为[['sum',['product',2,3],4]],而不是您问题中显示的['sum',['product',2,3],4]

    此解决方案将您的输入列表 ['sum',['product',2,3],4] 与其他测试一起使用。

    from operator import add, sub, mul, truediv
    
    funcs = {'sum': add, 'minus': sub, 'product': mul, 'divide': truediv}  # you can use your functions instead of this
    
    def process(seq):
        if isinstance(seq, list):
            return funcs[seq[0]](*(process(i) for i in seq[1:]))
        return seq
    
    print(process(['sum',['product',2,3],4]))
    print(process(['sum',['product',['minus', 2, 3],3],4]))
    print(process(['sum',['product',['minus', 2, 3],3],['divide', 3, 4]]))
    

    输出

    10
    1
    -2.25
    

    如果你想要一个班轮那么

    def process(seq):
        return seq if not isinstance(seq, list) else funcs[seq[0]](*map(process, seq[1:]))
    

    编辑:

    这不适用于我在评论中解释的情况,Ajax1234 的解决方案处理了这个问题并解释了他们更改输入列表和逻辑的原因。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多