views:

1754

answers:

9

I want to sort a list using my own cmp function. For the purpose of this discussion we can use the following example which is equivalent to what I'm trying to do:

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

However, because of the way I organized my code, I much prefer to put the definition of cmp_configs after the sort. However, I fail on:

NameError: name 'cmp_configs' is not defined

Is there any way to "declare" cmp_configs before it's used, which will make my code cleaner, or do I have to define it only before?

Note: 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.

Edit: A case in which may be necessary is:

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.

But now I understand that since spam and eggs are called inside functions then by the time I call either one of them both of them will already have been defined, so the only solution is in fact to reorganize the code.

+4  A: 

"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
+1  A: 

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
+2  A: 

What you can do is to wrap the invocation into a function of it's 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 (like in Pascal), but that it should be defined before it's usage.

Hope that helps.

Vanya
+4  A: 

If you don't like declaring a function before a use and declaring a function after is impossible, what about declaring it in some other module? Technically you still declare it before but it's clean.

You can create a recursion like the following:

def foo():
    bar()

def bar():
    foo()

(infinite, yes, but it works)

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 redeclare foo somewhere else down the code and bar will therefore call the new function.

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

(actually, it's not really 'anonymous', but I don't know what to call it)

RichN
+3  A: 

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
+2  A: 

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
+2  A: 

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
+1  A: 

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

Paul McGuire
A: 

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.

Mike Graham
How do I provide a less-than function?
Nathan Fellman
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