How do I forward-declare a function to avoid `NameError`s for functions defined later?

Viewed 223507

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

Sometimes, it is difficult to reorganize code to avoid this problem. For instance, when implementing some forms of recursion:

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?

17 Answers
# 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!

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

import test

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

TL;DR: Python does not need forward declarations. Simply put your function calls inside function def definitions, and you'll be fine.

def foo(count):
    print("foo "+str(count))
    if(count>0):
        bar(count-1)

def bar(count):
    print("bar "+str(count))
    if(count>0):
        foo(count-1)

foo(3)
print("Finished.")

recursive function definitions, perfectly successfully gives:

foo 3
bar 2
foo 1
bar 0
Finished.

However,

bug(13)

def bug(count):
    print("bug never runs "+str(count))

print("Does not print this.")

breaks at the top-level invocation of a function that hasn't been defined yet, and gives:

Traceback (most recent call last):
  File "./test1.py", line 1, in <module>
    bug(13)
NameError: name 'bug' is not defined

Python is an interpreted language, like Lisp. It has no type checking, only run-time function invocations, which succeed if the function name has been bound and fail if it's unbound.

Critically, a function def definition does not execute any of the funcalls inside its lines, it simply declares what the function body is going to consist of. Again, it doesn't even do type checking. So we can do this:

def uncalled():
    wild_eyed_undefined_function()
    print("I'm not invoked!")

print("Only run this one line.")

and it runs perfectly fine (!), with output

Only run this one line.

The key is the difference between definitions and invocations.

The interpreter executes everything that comes in at the top level, which means it tries to invoke it. If it's not inside a definition.
Your code is running into trouble because you attempted to invoke a function, at the top level in this case, before it was bound.

The solution is to put your non-top-level function invocations inside a function definition, then call that function sometime much later.

The business about "if __ main __" is an idiom based on this principle, but you have to understand why, instead of simply blindly following it.

There are certainly much more advanced topics concerning lambda functions and rebinding function names dynamically, but these are not what the OP was asking for. In addition, they can be solved using these same principles: (1) defs define a function, they do not invoke their lines; (2) you get in trouble when you invoke a function symbol that's unbound.

Python does not support forward declarations, but common workaround for this is use of the the following condition at the end of your script/code:

if __name__ == '__main__': main()

With this it will read entire file first and then evaluate condition and call main() function which will be able to call any forward declared function as it already read the entire file first. This condition leverages special variable __name__ which returns __main__ value whenever we run Python code from current file (when code was imported as a module, then __name__ returns module name).

Python technically has support for forward declaration.

if you define a function/class then set the body to pass, it will have an empty entry in the global table.

you can then "redefine" the function/class later on to implement the function/class.

unlike c/c++ forward declaration though, this does not work from outside the scope (i.e. another file) as they have their own "global" namespace

example:

def foo(): pass

foo()

def foo(): print("FOOOOO")

foo()

foo is declared both times however the first time foo is called it does not do anything as the body is just pass but the second time foo is called. it executes the new body of print("FOOOOO")

but again. note that this does not fix circular dependancies. this is because files have their own name and have their own definitions of functions

example 2:


class bar: pass

print(bar)

this prints <class '__main__.bar'> but if it was declared in another file it would be <class 'otherfile.foo'>

i know this post is old, but i though that this answer would be useful to anyone who keeps finding this post after the many years it has been posted for

Related