Python 无限循环和 if 语句



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

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 即使谓词不是 True。

我不明白的是 x>5 之后,当 pred 为 True 时, 为什么函数不以 if pred 结尾: 是因为没有返回值吗?即使我把返回then_clause或else_clause它仍然是一个无限循环。

我无法在 pythontutor 上测试这一点,因为它是无限递归。 谢谢你的时间。

Python 不允许你将x > 5等表达式作为代码传递给其他函数(至少,不像代码试图做的那样直接传递)。如果调用类似foo(x > 5)的函数,则会立即在调用方的作用域中计算x > 5表达式,并且仅将计算结果传递给被调用的函数。其他函数调用中的函数调用也会发生同样的情况。当Python看到foo(bar())时,它首先调用bar,然后调用foobar的返回值。

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))

请注意,对于then_funcelse_func,对我来说lambda有点奇怪,因为我们根本不关心或使用它们的返回值。lambda函数始终返回其表达式的结果。在这种情况下,这实际上是无害的,因为无论如何,printp都会返回None,这与如果我们没有明确地从常规(非lambda)函数中return,Python会为我们返回的内容相同。但至少对我来说,当返回值有意义时,使用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),但在更复杂的情况下可能是不可能的。

还值得注意的是,在调用new_if之前,2*x的评估会立即在p函数的作用域中进行。如果乘法是else_func逻辑中昂贵的部分,那可能会有问题(您希望将工作推迟到实际调用else_func的时间)。

你从自身调用函数,这会导致无限循环,你没有什么可以停止函数的。

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)

这将解决它

最新更新