是否可以在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
方法?这会让我的代码看起来更干净吗?
我假设有些人会试图告诉我,我应该重新组织我的代码,以便我没有这个问题。但是,有些情况下这可能是不可避免的,例如在实现某种形式的递归时。如果您不喜欢这个例子,假设我有一个案例,其中确实需要转发声明一个函数。
考虑这种情况,在Python中需要向前声明一个函数:
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
。
是重新组织代码并始终在调用之前放置定义的唯一解决方案吗?
如果你不想在使用之前定义一个函数,之后定义它是不可能的,那么在其他模块中定义它呢?
从技术上讲,你仍然首先定义它,但它很干净。
您可以创建如下的递归:
def foo():
bar()
def bar():
foo()
Python的函数是匿名的,就像值是匿名的,但它们可以绑定到一个名称。
在上面的代码中,foo()
不会调用名为foo的函数,它调用的函数恰好在调用时绑定到名称foo
。有可能在其他地方重新定义foo
,然后bar
将调用新函数。
你的问题无法解决,因为它就像要求获得一个尚未声明的变量。
导入文件本身。假设该文件名为test.py:
import test
if __name__=='__main__':
test.func()
else:
def func():
print('Func worked')
# declare a fake function (prototype) with no body
def foo(): pass
def bar():
# use the prototype however you see fit
print(foo(), "world!")
# define the actual function (overwriting the prototype)
def foo():
return "Hello,"
bar()
输出:
Hello, world!
“只是重新组织我的代码,以便我没有这个问题。”正确。容易做到。永远有效。
您可以在参考之前始终提供该功能。
“但是,有些情况下这可能是不可避免的,例如在实现某些形式的递归时”
看不出那是多么遥远的可能。请提供一个示例,说明在使用之前无法定义功能的地方。
现在等一下。当您的模块到达示例中的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
变量。
[编辑 - 下一部分结果不正确,因为在编译函数时将分配默认参数值,即使稍后更改cmp_configs的值,也将使用该值。]
幸运的是,Python是如此类型容纳,不关心你定义为cmp_configs
,所以你可以只用这句话作为序言:
cmp_configs = None
编译器会很高兴。在你调用cmp_configs
之前,一定要声明真正的fn
。
一种方法是创建处理函数。尽早定义处理程序,并将处理程序放在需要调用的所有方法之下。
然后,当您调用处理程序方法来调用函数时,它们将始终可用。
处理程序可以采用nameOfMethodToCall
参数。然后使用一堆if语句来调用正确的方法。
这将解决您的问题。
def foo():
print("foo")
#take input
nextAction=input('What would you like to do next?:')
return nextAction
def bar():
print("bar")
nextAction=input('What would you like to do next?:')
return nextAction
def handler(action):
if(action=="foo"):
nextAction = foo()
elif(action=="bar"):
nextAction = bar()
else:
print("You entered invalid input, defaulting to bar")
nextAction = "bar"
return nextAction
nextAction=input('What would you like to do next?:')
while 1:
nextAction = handler(nextAction)
是的,我们可以检查一下。
print_lyrics()
def print_lyrics():
print("I'm a lumberjack, and I'm okay.")
print("I sleep all night and I work all day.")
def repeat_lyrics():
print_lyrics()
print_lyrics()
repeat_lyrics()
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
正如BJ Homer在上面提到的注释中所提到的,Python中的一般规则并不是代码中应该定义更高的函数(如在Pascal中),而是应该在使用之前定义它。
希望有所帮助。
你可以做的是将调用包装成自己的函数。
以便
foo()
def foo():
print "Hi!"
会打破,但是
def bar():
foo()
def foo():
print "Hi!"
bar()
将正常工作。
Python
中的一般规则不是该函数应该在代码中定义得更高(如在Pascal
中),而是应该在使用之前定义它。
希望有所帮助。
如果您通过以下内容启动脚本:
if __name__=="__main__":
main()
那么你可能不必担心像“前瞻性宣言”这样的事情。你看,解释器会加载你所有的函数,然后启动你的main()函数。当然,确保你所有的进口都是正确的;-)
想想看,我从来没有在python中听到过“前向声明”这样的事情......但话又说回来,我可能错了;-)
如果对cmp_configs的调用在它自己的函数定义中,那么你应该没问题。我举个例子。
def a():
b() # b() hasn't been defined yet, but that's fine because at this point, we're not
# actually calling it. We're just defining what should happen when a() is called.
a() # This call fails, because b() hasn't been defined yet,
# and thus trying to run a() fails.
def b():
print "hi"
a() # This call succeeds because everything has been defined.
通常,将代码放在函数内(例如main())将解决您的问题;只需在文件末尾调用main()即可。
我为恢复这个线程而道歉,但是这里没有讨论可能适用的策略。
使用反射可以做类似于前向声明的事情。例如,假设您有一段代码如下所示:
# 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中,语句globals()[function_name]()
与foo()
相同,如果function_name = 'foo'
由于上面讨论的原因,因为python必须在调用它之前查找每个函数。如果要使用timeit
模块来查看这两个语句的比较,它们具有完全相同的计算成本。
当然这里的例子是非常无用的,但是如果一个人需要执行一个函数的复杂结构,但必须在之前声明(或者在结构上之后没有意义),可以只存储一个字符串,尝试稍后调用该函数。
不,我不相信有任何方法可以在Python中转发声明一个函数。
想象一下,你是Python解释器。当你到达线
print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])
要么你知道cmp_configs是什么,要么你不知道。为了继续,你必须知道cmp_configs。如果有递归则无关紧要。
像前向声明一样在python中没有这样的东西。您只需确保在需要之前声明您的函数。请注意,在执行函数之前,不会解释函数体。
请考虑以下示例:
def a():
b() # won't be resolved until a is invoked.
def b():
print "hello"
a() # here b is already defined so this line won't fail.
您可以认为函数的主体只是在调用函数后将被解释的另一个脚本。
有时,自上而下的算法最容易理解,从整体结构开始,深入细节。
你可以在没有前瞻声明的情况下这样做
def main():
make_omelet()
eat()
def make_omelet():
break_eggs()
whisk()
fry()
def break_eggs():
for egg in carton:
break(egg)
# ...
main()
你不能在Python中转发声明一个函数。如果在定义函数之前执行了逻辑,那么反正可能会遇到问题。将您的操作放在脚本末尾的if __name__ == '__main__'
中(通过执行一个名为“main”的函数,如果它是非平凡的)并且您的代码将更加模块化,并且您将能够将其用作模块,如果您曾经需要。
另外,用生成器表示替换该列表理解(即,print "\n".join(str(bla) for bla in sorted(mylist, cmp=cmp_configs))
)
另外,不要使用不推荐使用的cmp
。使用key
并提供小于功能。