遥远的最近 發表於 2019-11-5 09:41:00

python argparse:命令行参数解析详解

<h2 id="简介">简介</h2>
<p>本文介绍的是<em><strong>argparse</strong></em>模块的基本使用方法,尤其详细介绍<strong>add_argument</strong>内建方法各个参数的使用及其效果。</p>
<p>本文翻译自argparse的官方说明,并加上一些笔者的理解</p>
<pre><code class="language-Python">import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                  help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
                  const=sum, default=max,
                  help='sum the integers (default: find the max)')

args = parser.parse_args()
print(args.accumulate(args.integers))
</code></pre>
<p>如上示例,<em>argparse</em>模块的基本使用包含5个步骤:</p>
<ol>
<li>import模块:<em>import argparse</em></li>
<li>获解析器对象:<em>argparse.ArgumentParser</em></li>
<li>利用解析器对象内建方法,添加参数解析规则:<em>add_argument</em></li>
<li>利用解析器对象内建方法,开始解析参数,获取解析结果对象:<em>parse_args</em></li>
<li>从解析结果对象中,获取参数值:<em>parse_args</em></li>
</ol>
<h2 id="解析器类argumentparser">解析器类(ArgumentParser)</h2>
<p>在第2步中,我们通过<code>ArgumentParser()</code>函数的调用获取了解析器对象<code>ArgumentParser</code>。</p>
<p>在了解解析器对象的各个成员之前,我们先对一段正常的说明文本进行区间划分</p>
<pre><code># usage字段
usage: 程序名 [-h|--help] .....

# Description字段
程序功能描述

# 位置参数说明(必选)
positional arguments:
...

# 可选参数说明
optional arguments:
...

# 补充说明字段
...
</code></pre>
<p>例如</p>
<pre><code>usage: PROG [-h] [--foo ] bar

bar help

positional arguments:
bar          bar help

optional arguments:
-h, --help   show this help message and exit
--foo foo help

And that's how you'd foo a bar
</code></pre>
<p><em>关于位置参数与可选参数的理解,参考下一章节:添加参数解析规则</em></p>
<p>在上述的区间划的认识下,我们再来看看解析器对象的成员及其功能</p>
<table>
<thead>
<tr>
<th style="text-align: center">名字</th>
<th style="text-align: center">默认值</th>
<th style="text-align: left">功能</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">prog</td>
<td style="text-align: center">sys.argv</td>
<td style="text-align: left"><code>-h</code>时显示的程序名</td>
</tr>
<tr>
<td style="text-align: center">usage</td>
<td style="text-align: center">-</td>
<td style="text-align: left">usage字段描述</td>
</tr>
<tr>
<td style="text-align: center">description</td>
<td style="text-align: center">None</td>
<td style="text-align: left">description字段描述</td>
</tr>
<tr>
<td style="text-align: center">epilog</td>
<td style="text-align: center">None</td>
<td style="text-align: left">补充字段描述</td>
</tr>
<tr>
<td style="text-align: center">parents</td>
<td style="text-align: center">None</td>
<td style="text-align: left">从父(公共)解析器中继承所有的参数选项</td>
</tr>
<tr>
<td style="text-align: center">formatter_class</td>
<td style="text-align: center">None</td>
<td style="text-align: left">定制说明文本的显示风格</td>
</tr>
<tr>
<td style="text-align: center">prefix_class</td>
<td style="text-align: center">-</td>
<td style="text-align: left">定制前缀字符,例如前缀<strong>"-b"</strong>改为<strong>“+b"</strong></td>
</tr>
<tr>
<td style="text-align: center">add_help</td>
<td style="text-align: center">True</td>
<td style="text-align: left">是否使能显示参数 <code>-h --help</code></td>
</tr>
<tr>
<td style="text-align: center">allow_abbrev</td>
<td style="text-align: center">True</td>
<td style="text-align: left">是否支持长参数</td>
</tr>
<tr>
<td style="text-align: center">fromfile_prefix_chars</td>
<td style="text-align: center">None</td>
<td style="text-align: left">略</td>
</tr>
<tr>
<td style="text-align: center">argument_default</td>
<td style="text-align: center">None</td>
<td style="text-align: left">略</td>
</tr>
<tr>
<td style="text-align: center">conflict_handler</td>
<td style="text-align: center">None</td>
<td style="text-align: left">略</td>
</tr>
</tbody>
</table>
<p>比较常用的是<em><strong>description</strong></em>,例如:</p>
<pre><code>parser = argparse.ArgumentParser(description='Process some integers.')
</code></pre>
<p>或者</p>
<pre><code>parser = argparse.ArgumentParser()
parser.descritpioin="Process some integers."
</code></pre>
<h2 id="添加参数解析规则add_argument">添加参数解析规则(add_argument)</h2>
<p><em><strong>add_argument</strong></em>是解析器类<em><strong>ArgumentParser</strong></em>的内建方法,用于向解析器添加参数解析规则</p>
<pre><code>ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type]
                [, choices][, required][, help][, metavar][, dest])
</code></pre>
<p>内建方法支持以下的<strong>关键字</strong>,我们会对每一个关键字及其效果做进一步说明</p>
<table>
<thead>
<tr>
<th style="text-align: left">关键字</th>
<th style="text-align: left">简介</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">name or flags</td>
<td style="text-align: left">参数名或者"-/--"开头的选项,例如<code>foo</code>或者<code>-f, --foo</code></td>
</tr>
<tr>
<td style="text-align: left">action</td>
<td style="text-align: left">匹配到选项后的行为</td>
</tr>
<tr>
<td style="text-align: left">nargs</td>
<td style="text-align: left">选项跟随的参数个数</td>
</tr>
<tr>
<td style="text-align: left">const</td>
<td style="text-align: left">在某些<code>action</code>和<code>nargs</code>下,使用的固定值</td>
</tr>
<tr>
<td style="text-align: left">default</td>
<td style="text-align: left">默认值</td>
</tr>
<tr>
<td style="text-align: left">type</td>
<td style="text-align: left">参数类型</td>
</tr>
<tr>
<td style="text-align: left">choices</td>
<td style="text-align: left">可选的参数值范围</td>
</tr>
<tr>
<td style="text-align: left">required</td>
<td style="text-align: left">选项必选or可选</td>
</tr>
<tr>
<td style="text-align: left">help</td>
<td style="text-align: left">参数描述</td>
</tr>
<tr>
<td style="text-align: left">metavar</td>
<td style="text-align: left">使用说明中显示的参数名</td>
</tr>
<tr>
<td style="text-align: left">dest</td>
<td style="text-align: left">选项最终在解析结果对象中的名字</td>
</tr>
</tbody>
</table>
<h3 id="关键字name-or-flags">关键字name or flags</h3>
<p><strong>关键字name</strong>是什么?<strong>flags</strong>又是什么?两者有什么差别?</p>
<p><strong>name表示参数名,其赋值与位置顺序相关,因此也叫位置参数名,命令行中必须赋值</strong></p>
<p><strong>flags表示<code>-|--</code>开头的参数名,命令行中可选参数</strong></p>
<p>例如:</p>
<pre><code>#可选的flags参数
parser.add_argument('-f', '--foo')
#必选的name位置参数
parser.add_argument('bar0')
parser.add_argument('bar1')
</code></pre>
<p>这里假设<code>--foo</code>需要带1个参数,那么</p>
<pre><code>prog arg1 --foo arg2 arg3
</code></pre>
<ul>
<li>arg1 是位置参数bar0的值</li>
<li>arg2 是可选参数'-f, --foo'的值</li>
<li>arg3 是位置参数bar1的值</li>
</ul>
<p>换句话来说,在输入的命令行中,除去所有<code>-|--</code>开头的参数及其带上的参数值之外,剩下的参数都为位置参数,其顺序依次对应使用<em>add_argument</em>注册的位置参数顺序。</p>
<p><strong>在命令行调用中,位置参数必须赋值,即每个必选参数都要有赋值;而可选参数<code>(-|--)</code>可根据需求选择</strong></p>
<h3 id="关键字action">关键字action</h3>
<p>功能如其名,<strong>关键字action</strong>控制匹配到命令行选项后的行为。参数解析后不是保存值就好了?我们继续看看。</p>
<p><strong>关键字action</strong>只支持以下值,我们稍后再详细讲解每一个值的含义:</p>
<table>
<thead>
<tr>
<th style="text-align: left">值</th>
<th style="text-align: left">含义</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">store</td>
<td style="text-align: left">保存参数值</td>
</tr>
<tr>
<td style="text-align: left">store_const</td>
<td style="text-align: left">与<strong>关键字const</strong>配合使用,保存<strong>关键字const</strong>的值</td>
</tr>
<tr>
<td style="text-align: left">store_true</td>
<td style="text-align: left">保存值为<em>True</em></td>
</tr>
<tr>
<td style="text-align: left">store_false</td>
<td style="text-align: left">保存值为<em>False</em></td>
</tr>
<tr>
<td style="text-align: left">append</td>
<td style="text-align: left">保存多次选项值为列表</td>
</tr>
<tr>
<td style="text-align: left">append_const</td>
<td style="text-align: left">与<strong>关键字const</strong>配合使用,保存<strong>关键字const</strong>的值为列表</td>
</tr>
<tr>
<td style="text-align: left">const</td>
<td style="text-align: left">保存选项的出现次数</td>
</tr>
<tr>
<td style="text-align: left">help</td>
<td style="text-align: left">效果等效于<code>-h</code>和 <code>--help</code></td>
</tr>
<tr>
<td style="text-align: left">version</td>
<td style="text-align: left">打印版本</td>
</tr>
</tbody>
</table>
<h4 id="store">store</h4>
<p>保存参数值,这也是默认的行为,我们看个例子:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo')
&gt;&gt;&gt; parser.parse_args('--foo 1'.split())
Namespace(foo='1')
</code></pre>
<p>在<code>parse_args()</code>之后,<code>--foo</code>选项的值就保存到了<code>parse_args()</code>的解析结果对象中。</p>
<p>我们可以这样获取解析结果对象的值:</p>
<pre><code class="language-python">args = parser.parse_args('--foo 1'.split())
print(args.foo)
</code></pre>
<p>总结来说,<strong>选项名成为了解析结果对象的成员,而选项对应的值则成了成员的值</strong></p>
<p>到这里,我们存在2个疑惑:</p>
<ol>
<li>当同时支持<code>-f</code>和<code>--foo</code>时,生成的成员名是什么呢?能自定义名字么?</li>
<li>当<code>PROG -f</code>这样不需要带参数的选项,存储的成员值是什么样的呢?</li>
</ol>
<p>不用急,我们继续往下看</p>
<h4 id="store_const">store_const</h4>
<p>在匹配到选项后,存储<strong>关键字const</strong>的值,常用于命令行中不带参数的选项。例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo', action='store_const', const=42)
&gt;&gt;&gt; parser.parse_args(['--foo'])
Namespace(foo=42)
</code></pre>
<p>从上面的例子,我们可以看到,在匹配到<code>--foo</code>后,对应成员foo的保存为了<code>const参数</code>的值。</p>
<p>但更多时候,我们不带参数的选项更多只是表示布尔型的开关,这时候我们可用<code>store_true</code>或者<code>store_false</code></p>
<h4 id="store_true-和-store_false">store_true 和 store_false</h4>
<p><code>store_true</code>和<code>store_false</code>是一种特殊的<code>store_const</code>,存储的值类型为布尔型<code>True</code>或<code>False</code>。例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo', action='store_true')
&gt;&gt;&gt; parser.add_argument('--bar', action='store_false')
&gt;&gt;&gt; parser.add_argument('--baz', action='store_false')
&gt;&gt;&gt; parser.parse_args('--foo --bar'.split())
Namespace(foo=True, bar=False, baz=True)
</code></pre>
<p>示例中有3个布尔型“开关”,可以发现有以下特点:</p>
<ol>
<li><code>store_true</code>在匹配到命令选项后,保存为<code>True</code>;相对的,<code>store_false</code>保存为<code>False</code></li>
<li>当命令行中没匹配到开关后,例如示例中的<code>baz</code>,则保存为<code>store_false</code>的相反值<code>True</code></li>
</ol>
<h4 id="append">append</h4>
<p>把所有值保存为一个列表,常用于支持多次选项的情况,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo', action='append')
&gt;&gt;&gt; parser.parse_args('--foo 1 --foo 2'.split())
Namespace(foo=['1', '2'])
</code></pre>
<h4 id="append_const">append_const</h4>
<p>与<code>store_const</code>非常相似,只是把值存储为一个列表。此时如果没有指定<strong>关键字const</strong>,则默认为<code>None</code>。<code>append_const</code>常用于多个不同选项值需要存储到相同成员列表的情况。例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--str', dest='types', action='append_const', const=str)
&gt;&gt;&gt; parser.add_argument('--int', dest='types', action='append_const', const=int)
&gt;&gt;&gt; parser.parse_args('--str --int'.split())
Namespace(types=[&lt;class 'str'&gt;, &lt;class 'int'&gt;])
</code></pre>
<p>理解上文需要知道以下前提:</p>
<ol>
<li><strong>关键字dest</strong>用于指定成员名</li>
<li>参数的值可以是各种对象,包括类型对象,即示例中的<strong>str类型</strong>和<strong>int类型</strong></li>
</ol>
<p>在示例中,<code>--str</code>的常量值是<em><strong>str类型</strong></em>,以列表形式保存到<strong>types成员</strong>;<code>--int</code>的常量值是<em><strong>int类型</strong></em>,以列表形式保存到<strong>types成员</strong></p>
<h4 id="count">count</h4>
<p>如果我们只需要统计<strong>选项</strong>出现的次数,此处可以用<code>count</code>,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--verbose', '-v', action='count')
&gt;&gt;&gt; parser.parse_args(['-vvv'])
Namespace(verbose=3)
</code></pre>
<h4 id="help">help</h4>
<p>打印帮助信息,功能等效于<code>-h|--help</code></p>
<h4 id="version">version</h4>
<p>打印版本信息,需要配合<strong>关键字version</strong>使用,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; import argparse
&gt;&gt;&gt; parser = argparse.ArgumentParser(prog='PROG')
&gt;&gt;&gt; parser.add_argument('--version', action='version', version='%(prog)s 2.0')
&gt;&gt;&gt; parser.parse_args(['--version'])
PROG 2.0
</code></pre>
<h3 id="关键字nargs">关键字nargs</h3>
<p><strong>关键字nargs</strong>是<em>number argumemts</em>的缩写,表示选项有多少个参数,其支持以下值:</p>
<table>
<thead>
<tr>
<th style="text-align: center">值</th>
<th style="text-align: left">含义</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">N (an integer)</td>
<td style="text-align: left">收集N个参数到列表</td>
</tr>
<tr>
<td style="text-align: center">'?'</td>
<td style="text-align: left">无参数或单个参数</td>
</tr>
<tr>
<td style="text-align: center">'*'</td>
<td style="text-align: left">大于等于0个参数</td>
</tr>
<tr>
<td style="text-align: center">'+'</td>
<td style="text-align: left">大于等于1个参数</td>
</tr>
<tr>
<td style="text-align: center">argparse.REMAINDER</td>
<td style="text-align: left">只收集不解析</td>
</tr>
</tbody>
</table>
<p>当没有指定<strong>关键字nargs</strong>时,其实际的值取决于<strong>关键字action</strong>,例如当<code>action = "store"</code>时,默认获取1个参数,当<code>action = "store_true"</code>时,选项不需要带参数。</p>
<h4 id="n-an-integer">N (an integer)</h4>
<p>此处的<code>N</code>,表示一个整型数字,含义为选项需要提供N个参数。例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo', nargs=2)
&gt;&gt;&gt; parser.add_argument('bar', nargs=1)
&gt;&gt;&gt; parser.parse_args('c --foo a b'.split())
Namespace(bar=['c'], foo=['a', 'b'])
</code></pre>
<p>需要注意的是,当<code>nargs = 1</code>时,其并不等效于<strong>关键字nargs</strong>的默认情况。例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('bar0', nargs=1)
&gt;&gt;&gt; parser.add_argument('bar1')
&gt;&gt;&gt; parser.parse_args('a b'.split())
Namespace(bar0=['a'], bar1='b')
</code></pre>
<p>可以发现,<code>nargs = 1</code>时,例如bar0,其值是一个列表,一个只有1个元素的列表;而默认情况下,就是一个元素,官方称为<code>item</code>。</p>
<h4 id="_">'?'</h4>
<p><code>nargs='?'</code>可以实现3种场景:</p>
<ol>
<li>输入的命令行中,选项带参数时,值为附带的参数</li>
<li>输入的命令行中,没有改选项时,值为<strong>关键字default</strong>的值</li>
<li>输入的命令行中,有选项但没带参数时,值为<strong>关键字const</strong>的值(只适用于可选选项(flag))</li>
</ol>
<p>例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo', nargs='?', const='c', default='d')
&gt;&gt;&gt; parser.add_argument('bar', nargs='?', default='d')
&gt;&gt;&gt; parser.parse_args(['XX', '--foo', 'YY'])
Namespace(bar='XX', foo='YY')
&gt;&gt;&gt; parser.parse_args(['XX', '--foo'])
Namespace(bar='XX', foo='c')
&gt;&gt;&gt; parser.parse_args([])
Namespace(bar='d', foo='d')
</code></pre>
<p>一个更常用的场景,是实现可选的输入输出文件,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
...                     default=sys.stdin)
&gt;&gt;&gt; parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),
...                     default=sys.stdout)
&gt;&gt;&gt; parser.parse_args(['input.txt', 'output.txt'])
Namespace(infile=&lt;_io.TextIOWrapper name='input.txt' encoding='UTF-8'&gt;,
          outfile=&lt;_io.TextIOWrapper name='output.txt' encoding='UTF-8'&gt;)
&gt;&gt;&gt; parser.parse_args([])
Namespace(infile=&lt;_io.TextIOWrapper name='&lt;stdin&gt;' encoding='UTF-8'&gt;,
          outfile=&lt;_io.TextIOWrapper name='&lt;stdout&gt;' encoding='UTF-8'&gt;)
</code></pre>
<p>上述例子中,如果命令行没有指定input,则使用标准输入stdin;如果命令行没有指定output,则使用标准输出stdout</p>
<h4 id="_-1">'*'</h4>
<p><code>nargs=2</code>会限制一定要有2个参数,如果需要任意多个参数呢?我们可以用<code>nargs='*'</code>,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo', nargs='*')
&gt;&gt;&gt; parser.add_argument('--bar', nargs='*')
&gt;&gt;&gt; parser.add_argument('baz', nargs='*')
&gt;&gt;&gt; parser.parse_args('a b --foo x y --bar 1 2'.split())
Namespace(bar=['1', '2'], baz=['a', 'b'], foo=['x', 'y'])
</code></pre>
<p>与<code>nargs=N</code>相似,最终的值是列表类型。</p>
<h4 id="_-2">'+'</h4>
<p><code>nargs='+'</code>与<code>nargs='*'</code>从功能上非常相似,唯一不同的地方在于,<code>nargs='+'</code>要求至少要有1个参数,否则会报错。</p>
<p><code>'?'</code>,<code>'+'</code>与<code>'*'</code>的定义与正则表达式中的<code>?</code>,<code>+</code>和<code>*</code>非常相似</p>
<p>在正则表达式中,</p>
<ul>
<li>?:表示0或1个字符</li>
<li>+:表示大于等于1个字符</li>
<li>*:表示大于等于0个字符</li>
</ul>
<p>我们看个例子:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser(prog='PROG')
&gt;&gt;&gt; parser.add_argument('foo', nargs='+')
&gt;&gt;&gt; parser.parse_args(['a', 'b'])
Namespace(foo=['a', 'b'])
&gt;&gt;&gt; parser.parse_args([])
usage: PROG [-h] foo
PROG: error: the following arguments are required: foo
</code></pre>
<h4 id="argparseremainder">argparse.REMAINDER</h4>
<p><code>nargs=argparse.REMAINDER</code>常用于收集参数后传递给其他的命令行解析工具,其不会解析<code>-|--</code>,只是收集所有选项到列表。</p>
<p>例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser(prog='PROG')
&gt;&gt;&gt; parser.add_argument('--foo')
&gt;&gt;&gt; parser.add_argument('command')
&gt;&gt;&gt; parser.add_argument('args', nargs=argparse.REMAINDER)
&gt;&gt;&gt; print(parser.parse_args('--foo B cmd --arg1 XX ZZ'.split()))
Namespace(args=['--arg1', 'XX', 'ZZ'], command='cmd', foo='B')
</code></pre>
<p>上例中,<strong>argparse</strong>没有解析<code>args</code>选项的<code>--arg1</code>,而是全部收集到了一个列表</p>
<h3 id="关键字const">关键字const</h3>
<p>在<strong>关键字acton</strong>和<strong>关键字nargs</strong>中,其实已经涉及了<strong>关键字const</strong>的所有功能。</p>
<p><strong>关键字const</strong>只是存储一个常量值,在以下两种情况下才会使用:</p>
<ol>
<li><code>action='store_const'</code>或者<code>action='append_const'</code></li>
<li><code>nargs='?'</code></li>
</ol>
<p>当使用<code>action='store_const'</code>和<code>action='append_const'</code>时,<strong>关键字const</strong>必须提供,对其他的<strong>action关键字</strong>时,默认值为<code>None</code></p>
<h3 id="关键字default">关键字default</h3>
<p>有时候,选项不带参数,或者命令行没对应选项,这时候就可以使用默认值,而<strong>关键字default</strong>存储的就是默认值。默认情况下,<strong>关键字default</strong>的值为<code>None</code>。例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo', default=42)
&gt;&gt;&gt; parser.parse_args(['--foo', '2'])
Namespace(foo='2')
&gt;&gt;&gt; parser.parse_args([])
Namespace(foo=42)
</code></pre>
<p>如果<strong>关键字default</strong>赋值的是字符串,而<strong>关键字type</strong>有指定参数类型,那么就会把字符串转为<strong>关键字type</strong>指定的类型,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--length', default='10', type=int)
&gt;&gt;&gt; parser.add_argument('--width', default=10.5, type=int)
&gt;&gt;&gt; parser.parse_args()
Namespace(length=10, width=10.5)
</code></pre>
<p>如果<strong>关键字nargs</strong>为<code>?</code>或者<code>*</code>,那么default的值会在命令行没有参数时使用,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('foo', nargs='?', default=42)
&gt;&gt;&gt; parser.parse_args(['a'])
Namespace(foo='a')
&gt;&gt;&gt; parser.parse_args([])
Namespace(foo=42)
</code></pre>
<p><strong>关键字default</strong>也提供一种特殊用法:<code>default=argparse.SUPPRESS</code>。在这种情况下,如果命令行并没有匹配的选项,那么并不会在<strong>解析结果对象</strong>中添加选项对应的成员,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo', default=argparse.SUPPRESS)
&gt;&gt;&gt; parser.parse_args([])
Namespace()
&gt;&gt;&gt; parser.parse_args(['--foo', '1'])
Namespace(foo='1')
</code></pre>
<h3 id="关键字type">关键字type</h3>
<p>默认情况下,<strong>argparse</strong>解析的参数默认为<strong>字符串</strong>类型,当然也可以通过<strong>关键字type</strong>指定其他任何类型,例如<code>float</code>,<code>int</code>,甚至是文件类型<code>file</code>, 例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('foo', type=int)
&gt;&gt;&gt; parser.add_argument('bar', type=open)
&gt;&gt;&gt; parser.parse_args('2 temp.txt'.split())
Namespace(bar=&lt;_io.TextIOWrapper name='temp.txt' encoding='UTF-8'&gt;, foo=2)
</code></pre>
<p>如果<strong>关键字type</strong>指定的是文件类型,我们还可以通过```FileType('w')以可写形式打开文件,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('bar', type=argparse.FileType('w'))
&gt;&gt;&gt; parser.parse_args(['out.txt'])
Namespace(bar=&lt;_io.TextIOWrapper name='out.txt' encoding='UTF-8'&gt;)
</code></pre>
<p><strong>关键字type</strong>甚至能指定为函数,经过函数处理后的返回值作为参数值,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; def perfect_square(string):
...   value = int(string)
...   sqrt = math.sqrt(value)
...   if sqrt != int(sqrt):
...         msg = "%r is not a perfect square" % string
...         raise argparse.ArgumentTypeError(msg)
...   return value
...
&gt;&gt;&gt; parser = argparse.ArgumentParser(prog='PROG')
&gt;&gt;&gt; parser.add_argument('foo', type=perfect_square)
&gt;&gt;&gt; parser.parse_args(['9'])
Namespace(foo=9)
&gt;&gt;&gt; parser.parse_args(['7'])
usage: PROG [-h] foo
PROG: error: argument foo: '7' is not a perfect square
</code></pre>
<h3 id="关键字choices">关键字choices</h3>
<p>当我们需要限制选项的值范围,我们可以用<strong>关键字choices</strong>。<strong>关键字choices</strong>限定了参数值的可选列表,如果命令行提供的参数值不在列表中,则会报错,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser(prog='game.py')
&gt;&gt;&gt; parser.add_argument('move', choices=['rock', 'paper', 'scissors'])
&gt;&gt;&gt; parser.parse_args(['rock'])
Namespace(move='rock')
&gt;&gt;&gt; parser.parse_args(['fire'])
usage: game.py [-h] {rock,paper,scissors}
game.py: error: argument move: invalid choice: 'fire' (choose from 'rock',
'paper', 'scissors')
</code></pre>
<p>当然,需要注意的是,<strong>关键字choice</strong>的值必须符合<strong>关键字type</strong>指定的类型。</p>
<h3 id="关键字required">关键字required</h3>
<p>默认情况下,<code>-f</code>和<code>--foo</code>都是可选的,但如果需要改为<strong>必选</strong>,可以使用<strong>关键字required</strong>,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo', required=True)
&gt;&gt;&gt; parser.parse_args(['--foo', 'BAR'])
Namespace(foo='BAR')
&gt;&gt;&gt; parser.parse_args([])
usage: argparse.py [-h] [--foo FOO]
argparse.py: error: option --foo is required
</code></pre>
<h3 id="关键字help">关键字help</h3>
<p><strong>关键字help</strong>是选项的说明,在<code>-h</code>或者<code>--help</code>时会显示出来,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser(prog='frobble')
&gt;&gt;&gt; parser.add_argument('--foo', action='store_true',
...                     help='foo the bars before frobbling')
&gt;&gt;&gt; parser.add_argument('bar', nargs='+',
...                     help='one of the bars to be frobbled')
&gt;&gt;&gt; parser.parse_args(['-h'])
usage: frobble [-h] [--foo] bar

positional arguments:
bar   one of the bars to be frobbled

optional arguments:
-h, --helpshow this help message and exit
--foo   foo the bars before frobbling
</code></pre>
<p>当然,<strong>关键字help</strong>也支持格式化显示,<code>%(prog)s</code>和大部分<strong>add_argument()</strong>的关键字,包括<code>%(default)s</code>,<code>%(type)s</code>,等等,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser(prog='frobble')
&gt;&gt;&gt; parser.add_argument('bar', nargs='?', type=int, default=42,
...                     help='the bar to %(prog)s (default: %(default)s)')
&gt;&gt;&gt; parser.print_help()
usage: frobble [-h]

positional arguments:
bar   the bar to frobble (default: 42)

optional arguments:
-h, --helpshow this help message and exit
</code></pre>
<p>格式为<code>%(keyword)s</code>,如果需要显示<code>%</code>,就需要使用<code>%%</code></p>
<p>还存在一种特殊情况,假设我们不希望参数显示在<em>--help</em>中,我们可以用:<strong>argparse.SUPPRESS</strong>,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser(prog='frobble')
&gt;&gt;&gt; parser.add_argument('--foo', help=argparse.SUPPRESS)
&gt;&gt;&gt; parser.print_help()
usage: frobble [-h]

optional arguments:
-h, --helpshow this help message and exit
</code></pre>
<h3 id="关键字dest">关键字dest</h3>
<p><strong>argparse</strong>会把解析的结果保存成<em>解析结果对象</em>的属性,但是,属性名是什么呢?例如,<code>parser.add_argument(’-f','--foo')</code>,解析结果是保存在属性<code>f</code>中还是<code>foo</code>中?<strong>关键字dest</strong>就是用于定制属性名的。</p>
<p>我们先了解默认情况下,属性名是什么?</p>
<p><strong>对位置参数而言,关键字dest默认为第一个参数名</strong>,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('bar')
&gt;&gt;&gt; parser.parse_args(['XXX'])
Namespace(bar='XXX')
</code></pre>
<p><strong>对可选参数而言,关键字dest首选第一个出现的长参数名。如果没有长参数,则选择第一个短参数名。不管选择的是长参数还是短参数,都会把<code>-|---</code>给去掉,同时把名字中的<code>-</code>符号替换为<code>_</code>,以符合python的变量命名规则</strong>,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('-f', '--foo-bar', '--foo')
&gt;&gt;&gt; parser.add_argument('-x', '-y')
&gt;&gt;&gt; parser.parse_args('-f 1 -x 2'.split())
Namespace(foo_bar='1', x='2')
&gt;&gt;&gt; parser.parse_args('--foo 1 -y 2'.split())
Namespace(foo_bar='1', x='2')
</code></pre>
<p>我们再看看,如果定制属性名有什么效果?</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo', dest='bar')
&gt;&gt;&gt; parser.parse_args('--foo XXX'.split())
Namespace(bar='XXX')
</code></pre>
<h3 id="关键字metavar">关键字metavar</h3>
<p>在执行<code>-h|--help</code>,显示的帮助信息中,如何定制选项带的参数名呢?例如:</p>
<pre><code>-t T        loop times
</code></pre>
<p>我希望修改显示的<code>T</code>为<code>TIMES</code>,更直观。这时候我们就可以使用<strong>关键字metavar</strong>了。</p>
<p>在默认情况下,对<strong>位置参数</strong>,则会直接显示参数名,对<strong>可选参数</strong>,则会转为大写。例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo')
&gt;&gt;&gt; parser.add_argument('bar')
&gt;&gt;&gt; parser.parse_args('X --foo Y'.split())
Namespace(bar='X', foo='Y')
&gt;&gt;&gt; parser.print_help()
usage:[-h] [--foo FOO] bar

positional arguments:
bar

optional arguments:
-h, --helpshow this help message and exit
--foo FOO
</code></pre>
<p>上例中,<strong>位置参数bar</strong>直接显示为<em>bar</em>,而<strong>可选参数--foo</strong>带的参数名就转大写显示<em>FOO</em>。</p>
<p>如果我们定制显示的参数名,该怎么做呢?</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser()
&gt;&gt;&gt; parser.add_argument('--foo', metavar='YYY')
&gt;&gt;&gt; parser.add_argument('bar', metavar='XXX')
&gt;&gt;&gt; parser.parse_args('X --foo Y'.split())
Namespace(bar='X', foo='Y')
&gt;&gt;&gt; parser.print_help()
usage:[-h] [--foo YYY] XXX

positional arguments:
XXX

optional arguments:
-h, --helpshow this help message and exit
--foo YYY
</code></pre>
<p>当然,还存在一种特殊情况,就是有多个参数<code>nargs=N</code>,这时候<strong>关键字metavar</strong>可以以列表形式提供啦,例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser(prog='PROG')
&gt;&gt;&gt; parser.add_argument('-x', nargs=2)
&gt;&gt;&gt; parser.add_argument('--foo', nargs=2, metavar=('bar', 'baz'))
&gt;&gt;&gt; parser.print_help()
usage: PROG [-h] [-x X X] [--foo bar baz]

optional arguments:
-h, --help   show this help message and exit
-x X X
--foo bar baz
</code></pre>
<p>最后,有一点要注意的时,<strong>关键字metavar</strong>与<strong>关键字dest</strong>不一样的地方在于,<strong>关键字metavar仅仅只影响-h|--help的显示效果,关键dest则同时影响解析结果属性名</strong></p>
<h2 id="获取解析结果">获取解析结果</h2>
<p>在<em>action='store'</em>中提到:<strong>选项名成为了解析结果对象的成员,而选项对应的值则成了成员的值</strong>,所以如果我们需要获取解析后的结果,直接使用解析结果的成员值就好了。例如:</p>
<pre><code class="language-python">&gt;&gt;&gt; parser = argparse.ArgumentParser(prog='PROG')
&gt;&gt;&gt; parser.add_argument('-x', dest='xyz')
&gt;&gt;&gt; parser.add_argument('--foo', nargs=2, metavar=('bar', 'baz'))
&gt;&gt;&gt; args = parser.parse_args("--foo a b -x c".split())
&gt;&gt;&gt; print(args.foo)
&gt;&gt;&gt; ['a', 'b']
&gt;&gt;&gt; print(args.xyz)
&gt;&gt;&gt; c
</code></pre><br><br>
来源:https://www.cnblogs.com/gmpy/p/11796416.html
頁: [1]
查看完整版本: python argparse:命令行参数解析详解