9

I'm using Python 3 argparse to get command-line arguments. I have an optional argument with a default value. When I read its value, is it possible to know if the user manually inputted the value or is it default one?

Earlier, I had designed as above. Now, I want to store preferences from previous usage. So, if a user didn't input any value to the optional argument, I want to take the value from previous usage (if any). So, I want to determine whether the value came as a default value or user given value.

Edit 1: I have multiple arguments like this. I know I can remove default value for the arguments and assign them programmatically later. I just want to know if there is a simpler solution to this

5
  • when it is supposed to be a default value, you should have less arguments than when the user has to provide one, yes? You can just check how many arguments you are provided, and wrap that in a conditional. Commented Dec 15, 2018 at 9:04
  • Thing is I have multiple such arguments. So, I want to know which ones were provided by user and for which ones, default value was picked up. Commented Dec 15, 2018 at 9:08
  • Presumably you know what those defaults are, so you can check whether the value is the same as the default. Commented Dec 15, 2018 at 9:10
  • There is a possibility that user might input the default value :P Commented Dec 15, 2018 at 9:11
  • 1
    stackoverflow.com/questions/4480075/… seems helpful for you, but it's not really a duplicate so I'm not marking it. Commented Dec 15, 2018 at 9:20

2 Answers 2

6

if a user didn't input any value to the optional argument, I want to take the value from previous usage (if any). So, I want to determine whether the value came as a default value or user given value.

Then you don't want to supply a default value; make the parameter optional (e.g. Argparse optional positional arguments? ), and then explicitly check for its presence or absence in the resulting Namespace object and do the appropriate thing in your code logic - presumably, check for a value in previous usage and then supply a default as a last resort. (Think of default values as a shortcut logic to handle the absence of the value; you need more complicated logic, so better to replace that system than to try to work around it.)

Sign up to request clarification or add additional context in comments.

1 Comment

The value will be absent from the Namespace only if default=argparse.SUPPRESS.
2

The surest way of identifying whether the user has provided a value is to leave the default at the default None. There's nothing the user can say that will produce the same thing. Then after parsing all you need to do is:

if args.myval is None:
    # no user input, set my own special default
else:
    # user value

If you set the default=argparse.SUPPRESS, the attribute will be omitted from the args namespace. But testing for that case it a bit more awkward.

args.myval

will raise an error, which you could catch. Or you could use hasattr(args, 'myval'). Or handle the missing key invars(args)`.

Internally parse_args maintains a list (set actually) of Actions that it has 'seen'. That's used to test for required Actions. But that isn't available to users. If it were available, sophisticated users could perform a wider variety of co-occurrence tests.

In [28]: import argparse
In [29]: parser = argparse.ArgumentParser()
In [30]: a1 = parser.add_argument('-f','--foo')

Test without a value:

In [31]: args = parser.parse_args([])
In [32]: args
Out[32]: Namespace(foo=None)         # foo is present
In [33]: args.foo is None
Out[33]: True

Change the default to SUPPRESS:

In [35]: a1.default = argparse.SUPPRESS
In [36]: args = parser.parse_args([])
In [37]: args
Out[37]: Namespace()          # foo is missing
In [38]: args.foo
AttributeError: 'Namespace' object has no attribute 'foo'

We could put args.foo in a try: except AttributeError block.

In [39]: hasattr(args, 'foo')
Out[39]: False

Or dictionary testing for missing value

In [46]: vars(args)
Out[46]: {}
In [47]: vars(args).get('foo') is None
Out[47]: True
In [48]: 'foo' in vars(args)
Out[48]: False

A default is most useful when it provides a valid, useful value, and it saves you from extra testing after parsing.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.