0

I have a function:

def foo(a=0, b=0, c=0, val=0, someotherval=0):  
    print val + someotherval  

This function is called inside a file bar.py. When I run bar.py from the console, I want to pass the arguments to the function as a string:

>>python bar.py "val=3"  

So the function foo interprets it as:

foo(val=3)  

I have attempted to use the exec command. In my bar.py file:

import sys
cmdlinearg = sys.argv[1]    # capturing commandline argument
foo(exec(cmdlinearg))  

But I get a syntax error.
I understand that I can just pass the argument values themselves, but with a function with many arguments, I do not want the end user to enter 0s for unneeded arguments:

>>python bar.py "0" "0" "0" "3"  

Is there a way to accomplish this?

hazrmard
  • 3,397
  • 4
  • 22
  • 36
  • Just use [argparse](https://docs.python.org/3/library/argparse.html) – NightShadeQueen Jul 24 '15 at 17:27
  • The argparse-based solutions are probably what you are looking for, but you could do `eval("foo(" + sys.argv[1] +")")`. Bear in mind that [the use of eval() is questionable](http://stackoverflow.com/questions/1832940/is-using-eval-in-python-a-bad-practice). – deStrangis Jul 24 '15 at 17:41
  • From [here](http://stackoverflow.com/questions/2428117/casting-raw-strings-python) `cmdlinearg.encode('string-escape')` for pre Py3 `cmdlinearg.encode('unicode-escape')` for Py3.x – AMR Jul 24 '15 at 17:42

5 Answers5

2

I would rather do this the proper way and use argparse.

Your command line interface would look such as:

bar.py --a 0 --b 0 --c 0 --val 0 --someotherval 0

And the code something along:

import argparse

def main():
  parser = argparse.ArgumentParser()
  parser.add_argument('a', type=int, default=0)
  ...
  args = parser.parse_args()
  foo(a=args.a, b=args.b, c=args.c, var=args.val, someotherval=args.someotherval)

if __name__ == '__main__':
  main()
Ioan Alexandru Cucu
  • 11,981
  • 6
  • 37
  • 39
  • you can also do `foo(**vars(args))` if all the arguments pertain to `foo`. (`vars` converts to a dictionary, `**` unpacks it) – NightShadeQueen Jul 24 '15 at 17:35
  • @NightShadeQueen You could do that if the cmd line args match the function parameters. It's just that as the python zen mentions "explicit is better than implicit". I wouldn't like the idea of the code failing when adding a new cmd line argument (say --debug or whatever) – Ioan Alexandru Cucu Jul 24 '15 at 17:41
1

If you have no concern for safety, you can just do

exec('foo(%s)' % sys.argv[1])

Or this:

def getdict(**vals):
    return vals
kwargs = exec('getdict(%s)' % sys.argv[1])
foo(**kwargs)

However, if your concern is the user's ease of use, maybe you should take a look at argparse.

Alyssa Haroldsen
  • 3,652
  • 1
  • 20
  • 35
1

How about using the argparse for parsing the command line arguments?

Example -

import argparse

def foo(a=0, b=0, c=0, val=0, someotherval=0):  
    print(val + someotherval)

parser = argparse.ArgumentParser(description='Some Parser')
parser.add_argument('-a','--a',default=0,type=int,help="value for a")
parser.add_argument('-b','--b',default=0,type=int,help="value for a")
parser.add_argument('-c','--c',default=0,type=int,help="value for a")
parser.add_argument('-v','--val',default=0,type=int,help="value for a")
parser.add_argument('-s','--someotherval',default=0,type=int,help="value for a")
args = parser.parse_args()
foo(a=args.a,b=args.b,c=args.c,val=args.val,someotherval=args.someotherval)

Then you can call and get results like -

>python a.py
0

>python a.py --val 10
10

>python a.py --val 10 --someotherval 100
110
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
0

Take a look at this library: http://click.pocoo.org

It may be useful in your case.

import click

@click.command()
@click.option('-a', default=0)
@click.option('-b', default=0)
@click.option('-c', default=0)
@click.option('--val', default=0)
@click.option('--someotherval', default=0)
def foo(a, b, c, val, someotherval):  
    print val + someotherval

if __name__ == '__main__':
    foo()

However, you have to add use options as arguments, not strings:

>> python bar.py --val=3  
alexo_o
  • 637
  • 5
  • 16
-2

You could just default the values for the other parameters if you know that they are never going to enter them.

foo(0,0,exec(cmdlinearg),0)
Noah Hall-Potvin
  • 187
  • 1
  • 10
  • That won't work. One user might want to call foo(a=4), another might want to call foo(b=3, somotherval=10). – hazrmard Jul 24 '15 at 17:27