在Python中玩了一下,我发现以下代码如我所料地工作:
f = lambda S,b : (S if len(S)==b else f(S[1:],b))
从列表S,它将递归地删除第一个元素,直到S的长度等于b。例如f([1,2,3,4,5,6],3)=[4,5,6]。在
然而,令我大吃一惊的是,下面的解决方案使用了“三元hack”[a,b][c]而不是“b if c else a”(又名“c”?b: a“)不起作用:
^{pr2}$
这将超过最大递归深度。在
为什么这个不管用?在
(我知道这两个都不是优秀的编码风格的例子,但这与重点无关。)
Tags:
好,让我们看看lambda函数生成的
ast
:在vim中完成一些格式化后,我得到了:
^{pr2}$如您所见,在调用lambda时,代码执行的第一件事是创建元组,然后直接对同一lambda执行递归调用(
Call(Name('g'...
)。在首先要做的是调用,因为空列表的切片仍然是空列表:
这意味着
g(S[1:])
将减少您的列表,直到空列表,然后继续用空列表不断调用g
。这是因为解析器执行语句的方式。首先执行的是递归方法调用,因此它不会停止。在我的观点是:基本情况不适用于递归。在
希望这能给这个问题带来更多的启发。在
如果执行}中的一个(并返回结果),而如果执行},然后执行}
A if C else B
,则先执行C
,然后执行其中一个A
或{[B, A][C]
,则执行A
和{C
。您可以通过使用某个函数p("A") if p("C") else p("B")
和[p("B"), p("A")][p("C")]
来轻松检查这一点,该函数打印其输入,然后返回True
或{所以在第一种情况下,
S if len(S)==b else f(S[1:],b)
,递归调用只在条件不适用的情况下执行。然而,在第二种情况下,它甚至在条件被测试之前被执行,在递归调用的函数ad infinium中也是如此。在(我假设您不打算在实践中使用它,因此这可能并不重要,但无论如何:请注意:(1)这两个函数都缺少对case
len(S) < b
的保护,(2)使用S[-b:]
可以实现相同的效果,并且(3)使用if/else
当然,更具可读性。)我认为问题与三元运算符的工作原理有关。当使用三元运算符时,在检查条件之前将对两个表达式求值。在
因此在本例中,
g(S[1:],b)
甚至在到达if语句之前就得到了求值。在如果您有一个函数,那么没有与
^{pr2}$g(S[1:],b)
相同的基本情况S[1:]将到达它为空的点,如果它是空的,它将返回一个空列表。在
关于空列表的一个小例子:
相关问题 更多 >
编程相关推荐