Python无限循环和if语句

时间:2017-05-14 08:27:48

标签: python if-statement recursion

这个问题要求我确定以下代码的输出。

def new_if(pred, then_clause, else_clause):

    if pred:
        then_clause
    else:
        else_clause
def p(x):
    new_if(x>5, print(x), p(2*x))  
p(1)

我不明白为什么它会是一个无限循环。 输出1,2,4,8,16 ....等等。

据我所知,将print(x)作为参数传递即可 直接打印x,这就是为什么输出有1,2,4,即使谓词不是真的。

我不理解的是在x> 5之后,当pred为True时, 为什么函数不会在if pred结束: 是因为没有回报价值吗?即使我把return_clause或else_clause放回去,它仍然是一个无限循环。

我无法在pythontutor上测试这个,因为它是无限递归。 感谢您的时间。

2 个答案:

答案 0 :(得分:1)

你正在调用自身的函数,这会导致无限循环而你没有任何东西可以阻止这个函数。

def new_if(pred, then_clause, else_clause):
    if pred:
        then_clause
    else:
        else_clause
def p(x):
    if x<5:
        new_if(x>5, print(x),p(2*x))    
p(1)

这将解决它

答案 1 :(得分:1)

Python不允许将x > 5之类的表达式作为代码传递给其他函数(至少,不是直接代码试图这样做)。如果您调用foo(x > 5)之类的函数,则会在调用者的范围内立即评估x > 5表达式,并且只将评估的结果传递给正在运行的函数调用。其他函数调用中的函数调用也会发生同样的情况。当Python看到foo(bar())时,它会先调用bar,然后使用foo的返回值调用bar

p(x)函数中,代码正在尝试将p(2*x)传递给new_if函数,但自new_if以来,解释器永远不会到达p调用会一直保持递归(或者更确切地说,直到超出最大递归深度引发异常)。

使代码工作的一种方法是将表达式放入lambda函数,并更改new_if来调用它们。将代码捆绑到函数中可以延迟表达式的求值,直到调用函数,并且没有无限递归,因为pred_func通常会在某个时刻返回True(虽然如果你打电话给p(0)p(-1),它仍然可以永远递归:

def new_if(pred_func, then_func, else_func):
    if pred_func():
        then_func()
    else:
        else_func()

def p(x):
    new_if(lambda: x>5, lambda: print(x), lambda: p(2*x))

请注意lambdathen_funcelse_func感到有点奇怪,因为我们根本不关心或使用它们的返回值。 lambda函数始终返回其表达式的结果。在这种情况下,这实际上是非常无害的,因为无论如何printp都会返回None,这与Python为我们返回的内容相同,如果我们没有这样做的话。从常规(非return)函数中明确lambda。但至少对我来说,当返回值意味着什么时,使用lambda似乎更自然。 (也许new_if应该return从它调用的函数返回的值?)

如果您不想编写闭包(即必须在封闭范围内查找x的函数),您可以使用functools.partial将预先计算的参数绑定到函数之类的printp没有立即调用这些函数。例如:

from functools import partial

def p(x):
    return new_if(partial((5).__lt__, x), partial(print, x), partial(p, 2*x))

仅当每个表达式都可以转换为对现有函数的单个调用时,此方法才有效。在这种情况下可以完成(对pred_func有一点创造性和细致的语法),但在更复杂的情况下可能无法实现。

值得注意的是,在2*x调用p之前,new_if范围内的else_func评估会立即发生。如果该乘法是else_func逻辑的昂贵部分,则可能会出现问题(您希望将工作推迟到实际调用{{1}}时)。