How to use optional positional arguments with nargs='*' arguments in argparse?
<p>As shown in the following code, I want to have an optional positional argument <code>files</code>, I want to specify a default value for it, when paths are passed in, use specified path.</p>

<p>But because <code>--bar</code> can have multiple arguments, the path passed in didn't go into <code>args.files</code>, how do I fix that? Thanks!</p>

<pre><code>import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
parser.add_argument('--bar', nargs='*')
parser.add_argument('files', nargs='?')

cmd = '--foo a --bar b c d '
print parser.parse_args(cmd.split())
# Namespace(bar=['b', 'c', 'd'], files=None, foo='a')


cmd = '--foo a --bar b c d /path/to/file1'
print parser.parse_args(cmd.split())
# Namespace(bar=['b', 'c', 'd', '/path/to/file1'], files=None, foo='a')
</code></pre>

<p>Your argument spec is inherently ambiguous (since <code>--bar</code> can take infinite arguments, there is no good way to tell when it ends, particularly since <code>files</code> is optional), so it requires user disambiguation. Specifically, <code>argparse</code> can be told "this is the end of the switches section, all subsequent argument are positional" by putting <code>--</code> before the positional only section. If you do:</p>

<pre><code>cmd = '--foo a --bar b c d -- /path/to/file1'
print parser.parse_args(cmd.split())
</code></pre>

<p>You should get:</p>

<pre><code>Namespace(bar=['b', 'c', 'd'], files='/path/to/file1', foo='a')
</code></pre>

<p>(Tested on Py3, but should apply to Py2 as well)</p>

<p>Alternatively, the user can pass the positional argument anywhere it's unambiguous by avoiding putting positional arguments after <code>--bar</code> e.g.:</p>

<pre><code>cmd = '/path/to/file1 --foo a --bar b c d'
</code></pre>

<p>or</p>

<pre><code>cmd = '--foo a /path/to/file1 --bar b c d'
</code></pre>

<p>Lastly, you could avoid using <code>nargs='*'</code> for switches, given the ambiguity it introduces. Instead, define <code>--bar</code> to be accepted multiple times with a single value per switch, accumulating all uses to a <code>list</code>:</p>

<pre><code>parser.add_argument('--bar', action='append')
</code></pre>

<p>then you pass <code>--bar</code> multiple times to supply multiple values one at a time, instead of passing it once with many values:</p>

<pre><code>cmd = '--foo a --bar b --bar c --bar d /path/to/file1'
</code></pre>

python parsing argparse optparse optional-arguments