309

I would like to have a optional argument that will default to a value if only the flag is present with no value specified, but store a user-specified value instead of the default if the user specifies a value. Is there already an action available for this?

An example:

python script.py --example
# args.example would equal a default value of 1
python script.py --example 2
# args.example would equal a default value of 2

I can create an action, but wanted to see if there was an existing way to do this.

Mr_and_Mrs_D
  • 32,208
  • 39
  • 178
  • 361
Rob
  • 7,377
  • 7
  • 36
  • 38

2 Answers2

432
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--example', nargs='?', const=1, type=int)
args = parser.parse_args()
print(args)

% test.py 
Namespace(example=None)
% test.py --example
Namespace(example=1)
% test.py --example 2
Namespace(example=2)

  • nargs='?' means 0-or-1 arguments
  • const=1 sets the default when there are 0 arguments
  • type=int converts the argument to int

If you want test.py to set example to 1 even if no --example is specified, then include default=1. That is, with

parser.add_argument('--example', nargs='?', const=1, type=int, default=1)

then

% test.py 
Namespace(example=1)
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 1
    How to do this with strings? I have a dilemma with differentiation of "" (empty string as default) and "" (empty string as entered by user). In the code for now I'm using the default and since I need to do some ops, I have something like this `self.foo = (args.bar or some_else_source).upper()`. It will break on None object AFAIUC. – 0andriy Aug 12 '19 at 14:02
  • 3
    BE CAREFUL; if you try to have positional args **afterwards**, the first position arg will become the value for `--example` (if it doesn't have an explicit one). Just spent 10 minutes debugging that! – dsz Jul 28 '22 at 00:02
  • 1
    is there a way to make it accept an optional int and still distinguish a positional string argument? – Frederick Nord Jul 13 '23 at 19:28
97

The difference between:

parser.add_argument("--debug", help="Debug", nargs='?', type=int, const=1, default=7)

and

parser.add_argument("--debug", help="Debug", nargs='?', type=int, const=1)

is thus:

myscript.py => debug is 7 (from default) in the first case and "None" in the second

myscript.py --debug => debug is 1 in each case

myscript.py --debug 2 => debug is 2 in each case

Murray
  • 1,129
  • 6
  • 2
  • 4
    Excellent way to describe this difference – TurnipEntropy Mar 21 '21 at 16:07
  • There is a contradiction between your answer and the previous answer... According to previous answer: myscript.py --debug should bring 7 – urie Jul 21 '22 at 07:59
  • You’re welcome to test the code for yourself. If I’ve made a mistake it’s helpful for us all. However, I believe I have correctly described the results of my testing. Test.py gives 7 because no —debug argument was provided so the default value is used. Test.py —debug gives 1, the value set by const. – Murray Jul 22 '22 at 11:44
  • There may be issues with running code, but this answer does correctly demonstrate how to assign default values with argparse, which is the crux of the question. – AwfulPersimmon May 12 '23 at 17:03