是否有可能在Python中前向声明一个函数?我想在声明之前使用我自己的cmp函数对列表进行排序。

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

我把cmp_configs方法的定义放在调用之后。它会失败,报错如下:

NameError: name 'cmp_configs' is not defined

是否有任何方法在使用cmp_configs方法之前“声明”它?

有时候,很难重新组织代码来避免这个问题。例如,在实现某些形式的递归时:

def spam():
    if end_condition():
        return end_result()
    else:
        return eggs()

def eggs():
    if end_condition():
        return end_result()
    else:
        return spam()

其中end_condition和end_result已经在前面定义。

唯一的解决方案是重新组织代码并始终在调用之前放置定义吗?


当前回答

不,我不相信有任何方法可以在Python中前向声明一个函数。

假设您是Python解释器。当你走到排队的时候

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

您可能知道cmp_configs是什么,也可能不知道。为了继续,你必须 知道cmp_configs。不管有没有递归。

其他回答

我很抱歉恢复这个话题,但有一个策略没有在这里讨论,但可能适用。

使用反射可以做一些类似于前向声明的事情。例如,假设你有这样一段代码:

# We want to call a function called 'foo', but it hasn't been defined yet.
function_name = 'foo'
# Calling at this point would produce an error

# Here is the definition
def foo():
    bar()

# Note that at this point the function is defined
    # Time for some reflection...
globals()[function_name]()

因此,通过这种方式,我们已经确定了在实际定义函数之前要调用哪个函数,这实际上是一种前向声明。在python中,由于上述原因,如果function_name = 'foo',语句globals()[function_name]()与foo()相同,因为python必须在调用每个函数之前查找它。如果使用timeit模块来比较这两个语句,它们具有完全相同的计算成本。

当然,这里的例子是非常无用的,但如果有一个复杂的结构,需要执行一个函数,但必须在之前声明(或者在结构上,之后声明没有什么意义),可以只存储一个字符串,然后尝试调用函数。

现在等一下。当您的模块到达示例中的print语句时,在定义cmp_configs之前,您到底希望它做什么?

如果你用print发布的问题实际上是想表达这样的东西:

fn = lambda mylist:"\n".join([str(bla)
                         for bla in sorted(mylist, cmp = cmp_configs)])

那么在执行这条语句之前就不需要定义cmp_configs了,只要在后面的代码中定义它就可以了。

现在如果你试图引用cmp_configs作为lambda参数的默认值,那么这是一个不同的故事:

fn = lambda mylist,cmp_configs=cmp_configs : \
    "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

现在,您需要在到达这一行之前定义一个cmp_configs变量。

[EDIT -接下来的部分被证明是不正确的,因为默认参数值将在函数编译时被赋值,即使您稍后更改cmp_configs的值,该值也将被使用。]

幸运的是,Python是如此适应类型,并不关心你定义什么为cmp_configs,所以你可以用这句话开始:

cmp_configs = None

这样编译器就高兴了。只要确保在调用fn之前声明真正的cmp_configs即可。

如果您不想在使用函数之前定义它,并且在使用之后定义它是不可能的,那么在其他模块中定义它呢?

从技术上讲,您仍然先定义它,但它是干净的。

你可以创建一个像下面这样的递归:

def foo():
    bar()

def bar():
    foo()

Python的函数是匿名的,就像值是匿名的一样,但是它们可以绑定到一个名称。

在上面的代码中,foo()并不调用foo名称的函数,它调用的函数恰好在调用时绑定到foo名称。可以在其他地方重新定义foo,然后bar将调用新函数。

您的问题无法解决,因为这就像要求获得一个未声明的变量。

“重新组织我的代码,这样我就不会有这个问题了。”正确的。很容易做到。总是工作。

您总是可以在引用函数之前提供该函数。

“然而,在某些情况下,这可能是不可避免的,例如在实现某些形式的递归时”

我看不出这有什么可能。请举例说明在使用之前不能定义函数的地方。

Python不支持前向声明,但常见的解决方法是在脚本/代码的末尾使用以下条件:

if __name__ == '__main__': main()

这样,它将首先读取整个文件,然后计算condition并调用main()函数,该函数将能够调用任何前向声明的函数,因为它已经首先读取了整个文件。此条件利用特殊变量__name__,当我们从当前文件运行Python代码时,该变量返回__main__值(当代码作为模块导入时,__name__返回模块名)。