是否可以在Python中向前声明一个函数?

问题:是否可以在Python中向前声明一个函数?

是否可以在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_conditionend_result先前已经被定义。

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

Is it possible to forward-declare a function in Python? I want to sort a list using my own cmp function before it is declared.

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

I’ve organized my code to put the definition of cmp_configs method after the invocation. It fails with this error:

NameError: name 'cmp_configs' is not defined

Is there any way to “declare” cmp_configs method before it’s used? It would make my code look cleaner?

I assume that some people will be tempted to tell me that I should just reorganize my code so that I don’t have this problem. However, there are cases when this is probably unavoidable, for instance when implementing some forms of recursion. If you don’t like this example, assume that I have a case in which it’s really necessary to forward declare a function.

Consider this case where forward-declaring a function would be necessary in Python:

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

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

Where end_condition and end_result have been previously defined.

Is the only solution to reorganize the code and always put definitions before invocations?


回答 0

如果您不想使用某个函数之前先定义它,而以后再定义它是不可能的,那么在其他模块中定义该函数呢?

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

您可以创建如下所示的递归:

def foo():
    bar()

def bar():
    foo()

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

在上面的代码中,foo()没有调用名称为foo的函数,而是调用了恰好在调用时绑定到名称的函数foo。可以在foo其他地方重新定义,bar然后调用新函数。

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

If you don’t want to define a function before it’s used, and defining it afterwards is impossible, what about defining it in some other module?

Technically you still define it first, but it’s clean.

You could create a recursion like the following:

def foo():
    bar()

def bar():
    foo()

Python’s functions are anonymous just like values are anonymous, yet they can be bound to a name.

In the above code, foo() does not call a function with the name foo, it calls a function that happens to be bound to the name foo at the point the call is made. It is possible to redefine foo somewhere else, and bar would then call the new function.

Your problem cannot be solved because it’s like asking to get a variable which has not been declared.


回答 1

您可以做的是将调用包装成它自己的函数。

以便

foo()

def foo():
    print "Hi!"

会破裂,但是

def bar():
    foo()

def foo():
    print "Hi!"

bar()

将正常工作。

一般的规则Python不是该功能应与代码(如中定义更高Pascal),但它应该它的使用之前定义。

希望有帮助。

What you can do is to wrap the invocation into a function of its own.

So that

foo()

def foo():
    print "Hi!"

will break, but

def bar():
    foo()

def foo():
    print "Hi!"

bar()

will be working properly.

General rule in Python is not that function should be defined higher in the code (as in Pascal), but that it should be defined before its usage.

Hope that helps.


回答 2

如果您通过以下方式启动脚本:

if __name__=="__main__":
   main()

那么您可能不必担心“转发声明”之类的问题。您会看到,解释器将加载所有函数,然后启动main()函数。当然,也请确保所有进口货都正确;-)

想一想,我从未在python中听到过“前向声明”之类的信息……但话又说回来,我可能错了;-)

If you kick-start your script through the following:

if __name__=="__main__":
   main()

then you probably do not have to worry about things like “forward declaration”. You see, the interpreter would go loading up all your functions and then start your main() function. Of course, make sure you have all the imports correct too ;-)

Come to think of it, I’ve never heard such a thing as “forward declaration” in python… but then again, I might be wrong ;-)


回答 3

如果对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()即可。

If the call to cmp_configs is inside its own function definition, you should be fine. I’ll give an example.

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.

In general, putting your code inside functions (such as main()) will resolve your problem; just call main() at the end of the file.


回答 4

我为恢复该线程表示歉意,但是这里没有讨论可能适用的策略。

使用反射可以做一些类似于转发声明的事情。例如,假设您有一段代码如下:

# 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模块来查看这两个语句的比较结果,则它们具有完全相同的计算成本。

当然,这里的示例是没有用的,但是如果要有一个复杂的结构来执行一个函数,但是必须在执行之前声明它(或者从结构上讲,在事后拥有它就没有意义了),那么可以只存储一个字符串并稍后尝试调用该函数。

I apologize for reviving this thread, but there was a strategy not discussed here which may be applicable.

Using reflection it is possible to do something akin to forward declaration. For instance lets say you have a section of code that looks like this:

# 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]()

So in this way we have determined what function we want to call before it is actually defined, effectively a forward declaration. In python the statement globals()[function_name]() is the same as foo() if function_name = 'foo' for the reasons discussed above, since python must lookup each function before calling it. If one were to use the timeit module to see how these two statements compare, they have the exact same computational cost.

Of course the example here is very useless, but if one were to have a complex structure which needed to execute a function, but must be declared before (or structurally it makes little sense to have it afterwards), one can just store a string and try to call the function later.


回答 5

在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.

您可以认为函数的主体只是调用该函数后将被解释的另一个脚本。

There is no such thing in python like forward declaration. You just have to make sure that your function is declared before it is needed. Note that the body of a function isn’t interpreted until the function is executed.

Consider the following example:

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.

You can think that a body of a function is just another script that will be interpreted once you call the function.


回答 6

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

假设您是Python解释器。当你上线时

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

您要么知道cmp_configs是什么,要么不知道。为了继续,您必须了解cmp_configs。是否存在递归无关紧要。

No, I don’t believe there is any way to forward-declare a function in Python.

Imagine you are the Python interpreter. When you get to the line

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

either you know what cmp_configs is or you don’t. In order to proceed, you have to know cmp_configs. It doesn’t matter if there is recursion.


回答 7

有时,从总体结构开始并深入研究细节,从上而下最容易理解算法。

您可以不使用前向声明而这样做:

def main():
  make_omelet()
  eat()

def make_omelet():
  break_eggs()
  whisk()
  fry()

def break_eggs():
  for egg in carton:
    break(egg)

# ...

main()

Sometimes an algorithm is easiest to understand top-down, starting with the overall structure and drilling down into the details.

You can do so without forward declarations:

def main():
  make_omelet()
  eat()

def make_omelet():
  break_eggs()
  whisk()
  fry()

def break_eggs():
  for egg in carton:
    break(egg)

# ...

main()

回答 8

# 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!
# 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()

Output:

Hello, world!

回答 9

您无法在Python中向前声明一个函数。如果在定义函数之前先执行逻辑,那么无论如何都可能会遇到问题。将您的动作放在if __name__ == '__main__'脚本的末尾(通过执行一个函数,如果不平凡则将其命名为“ main”),并且您的代码将更具模块化,并且如果需要,您可以将其用作模块至。

另外,用生成器表达(即print "\n".join(str(bla) for bla in sorted(mylist, cmp=cmp_configs)))替换该列表理解

另外,请勿使用cmp已弃用的。使用key并提供小于功能。

You can’t forward-declare a function in Python. If you have logic executing before you’ve defined functions, you’ve probably got a problem anyways. Put your action in an if __name__ == '__main__' at the end of your script (by executing a function you name “main” if it’s non-trivial) and your code will be more modular and you’ll be able to use it as a module if you ever need to.

Also, replace that list comprehension with a generator express (i.e., print "\n".join(str(bla) for bla in sorted(mylist, cmp=cmp_configs)))

Also, don’t use cmp, which is deprecated. Use key and provide a less-than function.


回答 10

导入文件本身。假设文件名为test.py:

import test

if __name__=='__main__':
    test.func()
else:
    def func():
        print('Func worked')

Import the file itself. Assuming the file is called test.py:

import test

if __name__=='__main__':
    test.func()
else:
    def func():
        print('Func worked')

回答 11

“只是重新组织我的代码,这样我就不会遇到这个问题。” 正确。容易做。一直有效。

您始终可以在引用之前提供该功能。

“但是,在某些情况下,这可能是不可避免的,例如当实施某种形式的递归时”

看不到这是怎么可能的。请提供一个无法使用该功能的地方的示例。

“just reorganize my code so that I don’t have this problem.” Correct. Easy to do. Always works.

You can always provide the function prior to it’s reference.

“However, there are cases when this is probably unavoidable, for instance when implementing some forms of recursion”

Can’t see how that’s even remotely possible. Please provide an example of a place where you cannot define the function prior to it’s use.


回答 12

现在等一下。当您的模块到达示例中的print语句时,cmp_configs定义,您希望它执行什么操作?

如果您使用印刷品发布问题确实是在尝试代表以下内容:

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

Now wait a minute. When your module reaches the print statement in your example, before cmp_configs has been defined, what exactly is it that you expect it to do?

If your posting of a question using print is really trying to represent something like this:

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

then there is no requirement to define cmp_configs before executing this statement, just define it later in the code and all will be well.

Now if you are trying to reference cmp_configs as a default value of an argument to the lambda, then this is a different story:

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

Now you need a cmp_configs variable defined before you reach this line.

[EDIT – this next part turns out not to be correct, since the default argument value will get assigned when the function is compiled, and that value will be used even if you change the value of cmp_configs later.]

Fortunately, Python being so type-accommodating as it is, does not care what you define as cmp_configs, so you could just preface with this statement:

cmp_configs = None

And the compiler will be happy. Just be sure to declare the real cmp_configs before you ever invoke fn.


回答 13

一种方法是创建处理程序函数。尽早定义处理程序,并将处理程序置于您需要调用的所有方法的下方。

然后,当您调用处理程序方法来调用函数时,它们将始终可用。

处理程序可以接受参数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)

One way is to create a handler function. Define the handler early on, and put the handler below all the methods you need to call.

Then when you invoke the handler method to call your functions, they will always be available.

The handler could take an argument nameOfMethodToCall. Then uses a bunch of if statements to call the right method.

This would solve your issue.

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)

回答 14

是的,我们可以检查一下。

输入项

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中)在函数中定义更高的函数,而是应在使用函数之前对其进行定义。

希望有帮助。

Yes, we can check this.

Input

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

Output

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.

As BJ Homer mentioned over above comments, A general rule in Python is not that function should be defined higher in the code (as in Pascal), but that it should be defined before its usage.

Hope that helps.