Reputation: 401
I'm using python 2.7.13.
My goal is to have three possible arguments, with default values being set if no arguments are given by the user:
parser.add_argument("-r", nargs=3, default=(0, 1000, 50), type=int, help="Useful help text")
This doesn't work for me, and I can't find anywhere if it is possible to use default in such a way as above.
When running it as program.py -r
I get a an error: expected 3 argument(s)
But I also tried removing nargs completely and only having one default value:
parser.add_argument("-r", default=100)
Strangely enough, this doesn't work either. It requires at least one argument...
Anyone understand this?
Upvotes: 3
Views: 6293
Reputation: 231395
I'll illustrate the normal behavior of default
in argparse
(with a Ipython interactive session)
In [32]: parser = argparse.ArgumentParser()
Define 3 Actions:
In [33]: parser.add_argument('-r', nargs=3, type=int, default=(1,2,3));
In [35]: parser.add_argument('-f', default='DEFAULT');
In [37]: parser.add_argument('-g', nargs='?', default='DEFAULT', const='const');
The help
. Note that all Actions have [], indicating that they are optional:
In [39]: parser.print_help()
usage: ipython3 [-h] [-r R R R] [-f F] [-g [G]]
optional arguments:
-h, --help show this help message and exit
-r R R R
-f F
-g [G]
If called without any argments, all of the defaults appear in the args
namespace.
In [40]: parser.parse_args([]) # e.g python myprog.py
Out[40]: Namespace(f='DEFAULT', g='DEFAULT', r=(1, 2, 3))
Giving -r
with 3 numbers (as specified by the nargs)
In [41]: parser.parse_args('-r 4 5 6'.split())
Out[41]: Namespace(f='DEFAULT', g='DEFAULT', r=[4, 5, 6])
Specify one of the other flags. Note the remaining defaults
In [42]: parser.parse_args('-f other'.split())
Out[42]: Namespace(f='other', g='DEFAULT', r=(1, 2, 3))
-g
with nargs='?'
has another option. It can be given without arguments. In that case it gets the const
value.
In [43]: parser.parse_args('-f other -g'.split())
Out[43]: Namespace(f='other', g='const', r=(1, 2, 3))
In [44]: parser.parse_args('-f other -g more'.split())
Out[44]: Namespace(f='other', g='more', r=(1, 2, 3))
There isn't such a 3 way option for nargs=3
. You either provide the 3 values, or you don't use -r
. If you need to distinguish between 1) no-r flag, 2) r flag without arguments, and 3) r flat with 3 arguments, I'd suggest splitting functionality into 2 actions, one a 'store_true', and other that takes the 3 values.
Defaults in argparse
can be a complicated matter, with various ways of setting them, differences between string and non-string values, even a way of suppressing them. But I've shown the basic behavior.
Upvotes: 4
Reputation: 190
With your example you can either call the application without the -r
flag which would result in the default values. If you want to specify the values yourself you have to give them all.
If you would like to enter them independently you could try something like this:
# script.py
import argparse
def main1():
parser = argparse.ArgumentParser()
parser.add_argument("-r", nargs=3, default=(0, 1000, 50), type=int,
help="Useful help text")
args = parser.parse_args()
print(args)
def main2():
parser = argparse.ArgumentParser()
parser.add_argument("-r1", type=int, default=0, help="...")
parser.add_argument("-r2", type=int, default=1000, help="...")
parser.add_argument("-r3", type=int, default=50, help="...")
args = parser.parse_args()
print(args)
if __name__ == "__main__":
main1()
#main2()
You could call your implementation (main1
) like this:
$ python script.py
Namespace(r=(0, 1000, 50))
$ python script.py -r 1 2 3
Namespace(r=[1, 2, 3])
$ python script.py -r 1
usage: args.py [-h] [-r R R R]
args.py: error: argument -r: expected 3 arguments
Using separate arguments your invocations could be looking like this (main2
):
$ python script.py -r1 1 -r2 2 -r3 3
Namespace(r1=1, r2=2, r3=3)
$ python script.py -r1 1
Namespace(r1=1, r2=1000, r3=50)
$ python script.py -r2 2
Namespace(r1=0, r2=2, r3=50)
$ python script.py -r3 3
Namespace(r1=0, r2=1000, r3=3)
This could be a little bit more wordy if you want to change all values but it gives you more flexibility. I think you could even combine those two approaches using a mutually_exclusive_group.
Upvotes: 0
Reputation:
Why don't you use argv
?
Example:
import sys
def main(first=1, second=2, third=3):
print first,second,third
if __name__ == '__main__':
main(*sys.argv[1:]) # notice the * before sys.argv[1:]
You can test executing the file from console with different number of parameters:
python myprogram.py # will print 1 2 3
python myprogram.py 7 # will print 7 2 3
python myprogram.py 7 8 # will print 7 8 3
python myprogram.py 7 8 9 # will print 7 8 9
Upvotes: 0
Reputation:
You only need to call the argument -r if you are not using the default value. If you do call then you have to also pass a value (or as many values you define in nargs).
Try just calling program.py
Upvotes: 1