views:

51

answers:

3

I'm writing a python command line program which has some interdependent options, I would like for the user to be able to enter the options in whichever order they please.

Currently I am using the getopts library to parse the command line options, unfortunately that parses them in-order. I've thrown together a system of boolean flags to leave the processing of certain command line arguments until the one they're dependent on is processed, however I had the idea of using a Priority Queue of function calls which would execute after all the command line options are parsed.

I know that Python can store functions under variable names, but that seems to call the function at the same time.

For example:

help = obj.PrintHelp()
heapq.heappush(commandQ, (0, help))

Will print the help dialog immediately. How would I go about implementing my code such that it won't call PrintHelp() immediately upon assigning it a name.

EDIT: Oh i just realized I was pushing into a queue called help, that's my mistake.

Thanks for the tip on removing the () after PrintHelp.

What if I want to now call a function that requires more than the self argument?

myFun = obj.parseFile(path)
heapq.heappush(commandQ, (1, myFun))

Would I just make the tuple bigger and take the command line argument?

+2  A: 

If you heappush like this:

myFun = obj.parseFile
heapq.heappush(commandQ, (1, myFun, path))

then to later call the function, you could do this:

while commandQ:
    x=heapq.heappop(commandQ)
    func=x[1]
    args=x[2:]
    func(*args)

Use

help = obj.PrintHelp

without the parentheses. This makes help reference the function. Later, you can call the function with help().

Note also (if I understand your situation correctly), you could just use the optparse or (if you have Python2.7 or better) argparse modules in the standard library to handle the command-line options in any order.

PS. help is a built-in function in Python. Naming a variable help overrides the built-in, making it difficult (though not impossible) to access the built-in. Generally, it's a good idea not to overwrite the names of built-ins.

unutbu
Thanks for the help. Anyways, I realise I made a mistake in the heapq push line. But that being said, what if the function takes arguments?
Julian
+1  A: 

Instead of using getopts, I would suggest using optparse (argparse, if you are using a newer python version): most probably, you will get everything you need, already implemented.

That said, in your example code, you are actually calling the function, while you should simply get its name:

help = obj.PrintHelp 
heapq.heappush(help, (0, help)) 
Roberto Liffredo
A: 

If you want to store a complete function call in Python, you can do it one of two ways:

# option 1: hold the parameters separately
# I've also skipped saving the function in a 'help' variable'
heapq.heappush(commandQ, (0, obj.PrintHelp, param1, param2))

# later:
command = commandQ[0]
heapq.heappop(commandQ)
command[1](*command[2:]) # call the function (second item) with args (remainder of items)

Alternatively, you can use a helper to package the arguments up via lambda:

# option 2: build a no-argument anonymous function that knows what arguments
#           to give the real one
# module scope
def makeCall(func, *args):
    return lambda: func(*args)

# now you can:
help = makeCall(obj.PrintHelp, param1, param2)
heapq.heappush(commandQ, (0, help))

If you need keyword arguments, let me know and I'll edit to take care of those too.

Walter Mundt