266

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?

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319

17 Answers17

185

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 work properly.

The general rule in Python is that a function should be defined before its usage, which does not necessarily mean it needs to be higher in the code.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Vanya
  • 3,091
  • 2
  • 18
  • 12
110

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

jldupont
  • 93,734
  • 56
  • 203
  • 318
  • 24
    +1 most practical answer: If you put this code at the **bottom** of the outermost source file, then you're free to define in any order. – Bob Stein Oct 26 '14 at 16:19
  • 3
    Great tip; really helps me; as I much more prefer "top-down" programming versus bottom up. – GhostCat Aug 13 '15 at 11:43
  • What is the point of the ' if __name__ == "__main__": ' line? I can simply write myMain() (or whatever the "main" function's name is) at the end of the file. – ThomasRones Jan 24 '21 at 19:26
  • 1
    Won't work if you reference a Class as a type. eg. `class X: def som(self, y: Y) ... class Y: ...` – Phani Rithvij Mar 28 '21 at 12:23
87

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.

Borodin
  • 126,100
  • 9
  • 70
  • 144
RichN
  • 6,181
  • 3
  • 30
  • 38
  • 52
    in short, if you have _if \_\_name\_\_ == '\_\_main\_\_': main()_ as the last line in your script everything will be just fine! – Filipe Pina Aug 03 '11 at 12:24
  • 4
    @FilipePina I haven't understood your comment -- why can't you put the last line of the code as simply `main()` ? – Sanjay Manohar Apr 08 '13 at 16:27
  • 14
    @SanjayManohar: to avoid executing it on `import your_module` – jfs Jun 19 '13 at 13:41
  • 2
    I'd like to add - sometimes it's possible to circumvent these issues using lambdas since they are evaluated later. – Joe Feb 26 '15 at 14:47
  • 4
    W.r.t. "anonymous", you really mean "first-class objects". – danielm Jul 22 '15 at 20:48
  • @RichN: I hope you're happy with my edits. If it weren't for the confusion between *declare* and *define* I would have left it alone. I think your answer could have done without the explanation about anonymous values, as it will confuse people and it makes it look like you're unclear what you're talking about. Run time changes to the symbol table are irrelevant to the question and you should have skipped it. – Borodin May 27 '16 at 00:30
  • @FilipePina: What do you mean by "everything will be just fine"? What problem is it that doing so is supposed to solve? – HelloGoodbye Sep 19 '18 at 13:18
  • @HelloGoodbye not sure exactly what I had in my *7 years* ago, but it was probably something around that OP has that line outside a function. If the code is inside a function and the last line of the script/module calls the entry point (usually `main()`) there's no need to worry about the order functions are declared as, at that point (last line), all have been defined – Filipe Pina Sep 21 '18 at 10:22
  • @FilipePina Yeah, 7 years _is_ a quite long time. Anyway, maybe it does solve the problem when you are just using functions, but I end my script with `if __name__ == '__main__': main()` (although not on a single line) and I do have the same problem as OP. I'm trying to access a function from within a class I have defined above the function, though; maybe that's affecting the behavior. – HelloGoodbye Sep 21 '18 at 18:07
  • 1
    @HelloGoodbye I'm afraid I can't comment without seeing actual code but if you only call a function within another function, then it's always after it was declared... – Filipe Pina Sep 24 '18 at 09:16
  • @FilipePina What do you mean by "it's always after it was declared"? What do both "it" refer to? – HelloGoodbye Sep 24 '18 at 22:00
  • "Your problem cannot be solved because it's like asking to get a variable which has not been declared." Well, it can be and is solved in languages that separate the declaration of objects from their definitions. – Gene Callahan Jan 11 '19 at 03:11
  • The manner the code snippet is shown here is confusing. My first impression was that this meant to say something like this could actually be done -- whereas the intent is to show such a construction is not possible because of the fallacy explained thereafter. – shasan Jul 02 '19 at 23:29
  • This misses the boat. The OP is asking a much more basic question than you're answering. The correct answer is "put the invocation inside a function, instead of at the top level", and then, since the interpreter treats the function call as part of a definition, not an immediate instruction, recursive definitions are perfectly fine without requiring any forward declarations. The foo/bar example is perfectly fine and is NOT an example of a failed construction. – DragonLord Sep 28 '20 at 21:41
12

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.

KGardevoir
  • 445
  • 4
  • 9
11

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()
funroll
  • 35,925
  • 7
  • 54
  • 59
11

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.

BJ Homer
  • 48,806
  • 11
  • 116
  • 129
11

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.

Piotr Czapla
  • 25,734
  • 24
  • 99
  • 122
7

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.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 9
    well this is if your only doing one pass over the code. Some compilers (and I realise python in interpreted) do two passes, so that these things can be figured out. forward-declaration, or at least some kind of scoped discovery, would be really good. – Mark Lakewood Aug 26 '11 at 02:15
7
# 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!
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • This does work, but Pylance will tell you, 'Function declaration "foo" is obscured by a declaration of the same name'. `def foo(): pass` is not a declaration or prototype, it's a definition of a function that does nothing. That's my understanding. – Fauxcuss Mar 21 '23 at 17:11
  • @Fauxcuss ah yes I wrote this answer before I knew about linting tools. You can probably find a way to disable that message in-line for such a forward declaration... Some of the other answers to this question might just be more straightforward. – ctrl-alt-deliberate Jun 03 '23 at 04:06
5

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

import test

if __name__=='__main__':
    test.func()
else:
    def func():
        print('Func worked')
user10488833
  • 51
  • 1
  • 3
  • but you need to encapsulate all your code with if __name__ to avoid it to execute two times – arivero Oct 14 '20 at 15:52
  • Correct, I nowadays use a lot: ''' if \_\_name__ == '\_\_main\_\_': from test import func func() else: def func(): print('Func worked') ''' So it is in the end user preference. – user10488833 Nov 04 '20 at 15:07
4

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.

Delimitry
  • 2,987
  • 4
  • 30
  • 39
Mike Graham
  • 73,987
  • 14
  • 101
  • 130
  • How do I provide a less-than function? – Nathan Fellman Oct 20 '09 at 06:15
  • Instead of cmp_configs, you would define a function that takes two arguments and returns True if the first is less than the second and False otherwise. – Mike Graham Oct 25 '09 at 15:55
  • 1
    To those of us coming from a C-like background, there's nothing unreasonable about logic executing before functions are defined. Think: "multi-pass compiler". Sometimes it takes a while to adapt to the new languages :) – Luke H Mar 08 '12 at 00:59
3

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.

DragonLord
  • 6,395
  • 4
  • 36
  • 38
1

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

Mikhail
  • 2,181
  • 1
  • 17
  • 15
0

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

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • 1
    I have such a situation. I am trying to pass types in a function decorator, and the types are defined further down the module. I can't move the offending types up, because that would break the inheritance chain. – Joe Feb 26 '15 at 14:01
  • I fixed it by passing a lambda to my decorator instead of the actual type; but I wouldn't know how to fix it otherwise (that wouldn't require me to rearrange my inheritances) – Joe Feb 26 '15 at 14:44
  • " Easy to do. Always works." --- No. It does NOT always work. In very special cases it doesn't. – Regis May Feb 06 '23 at 06:54
0

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.

PaulMcG
  • 62,419
  • 16
  • 94
  • 130
0

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

-1

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)
Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
obesechicken13
  • 795
  • 1
  • 12
  • 24