python之参数解析模块argparse

2.7之后python不再对optparse模块进行扩展,python标准库推荐使用argparse模块对命令行进行解析。

简单入门

先来看个例子:

argparse_test.py:

import argparse

parser = argparse.ArgumentParser()
parser.parse_args()

运行程序:

ShanedeMBP:some_work shane$ python3 argparse_test.py --help
usage: argparse_test.py [-h]

optional arguments:
  -h, --help  show this help message and exit
ShanedeMBP:some_work shane$ python3 argparse_test.py --verbose
usage: argparse_test.py [-h]
argparse_test.py: error: unrecognized arguments: --verbose
ShanedeMBP:some_work shane$ python3 argparse_test.py foo
usage: argparse_test.py [-h]
argparse_test.py: error: unrecognized arguments: foo
ShanedeMBP:some_work shane$ 

结果分析:

  • 若不给参数而运行这个程序,将不会得到任何结果。
  • 第二条命名显示了使用的argparse的好处,你什么也没做,却得到了一个很好的帮助信息。
  • 我们无需人为设置--help参数,就能得到一个良好的帮助信息。但是若给其他参数(比如foo)就会产生一个错误。

位置参数

我们修改下脚本:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("echo")
args = parser.parse_args()

运行:

nedeMBP:some_work shane$ python3 argparse_test.py 
usage: argparse_test.py [-h] echo
argparse_test.py: error: the following arguments are required: echo
ShanedeMBP:some_work shane$ python3 argparse_test.py --help
usage: argparse_test.py [-h] echo

positional arguments:
  echo

optional arguments:
  -h, --help  show this help message and exit
ShanedeMBP:some_work shane$ python3 argparse_test.py foo


结果分析:

  • 这次,我们增加了一个add_argument()方法,用来设置程序可接受的命令行参数。
  • 现在要运行程序,就必须设置一个参数。
  • parse_args()方法实际上从我们的命令行参数中返回了一些数据,在上面的例子中是echo
  • 这个像“魔法”一样的过程,是argparse自动完成的。

尽管自动产生的帮助信息展示地很美观,但是我们仍然无法只根据echo这个参数知道它是做什么的。所以,我们增加了一些东西,使得它变得更有用。

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("echo",help=" echo the string you use here!")
args = parser.parse_args()
# print(args.echo)

运行结果

ShanedeMBP:some_work shane$ python3 argparse_test.py 
usage: argparse_test.py [-h] echo
ShanedeMBP:some_work shane$ python3 argparse_test.py foo
foo
ShanedeMBP:some_work shane$ python3 argparse_test.py -h
usage: argparse_test.py [-h] echo

positional arguments:
  echo        echo the string you use here!

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

再多一点改变:

import argparse

parser = argparse.ArgumentParser()
# parser.add_argument("echo",help=" echo the string you use here!")
parser.add_argument('square',help="input the digital number")
args = parser.parse_args()
print(args.square**2)

输出结果:

ShanedeMBP:some_work shane$ python3 argparse_test.py 4
Traceback (most recent call last):
  File "argparse_test.py", line 10, in <module>
    print(args.square**2)
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'

这个程序并不能正确运行,因为argparse会将输入当作字符串处理,所以我们需要设置它的类型:(type=int)

import argparse

parser = argparse.ArgumentParser()
# parser.add_argument("echo",help=" echo the string you use here!")
parser.add_argument('square',help="input the digital number",type=int)
args = parser.parse_args()
print(args.square**2)

运行结果:

ShanedeMBP:some_work shane$ python3 argparse_test.py 4
16
ShanedeMBP:some_work shane$ python3 argparse_test.py four
usage: argparse_test.py [-h] square
argparse_test.py: error: argument square: invalid int value: 'four'

这样,指定了type类型后,可自动识别类型,好方便有木有...

详解

import argparse

#创建一个解析对象
parser = argparse.ArgumentParser()
# parser.add_argument("echo",help=" echo the string you use here!")
#向对象中添加相关命令行参数或选项,每一个add_argument方法对应一个参数或选项
parser.add_argument('square',help="input the digital number",type=int)
#调用parse_args()方法进行解析
args = parser.parse_args()
print(args.square**2)

方法ArgumentParser

ArgumentParser(prog=None, usage=None,description=None, epilog=None, parents=[],formatter_class=argparse.HelpFormatter, prefix_chars='-',fromfile_prefix_chars=None, argument_default=None,conflict_handler='error', add_help=True)

这些参数都有默认值,当调用parser.print_help()或者运行程序时由于参数不正确(此时python解释器其实也是调用了pring_help()方法)时,会打印这些描述信息,一般只需要传递description参数,如上。

prog

程序的名字,默认为sys.argv[0],用来在help信息中描述程序的名称。

>>> parser = argparse.ArgumentParser(prog='myprogram')
>>> parser.print_help()
usage: myprogram [-h]

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

usage

描述程序用途的字符串

>>> parser = argparse.ArgumentParser(prog='PROG', usage='%(prog)s [options]')
>>> parser.add_argument('--foo', nargs='?', help='foo help')
>>> parser.add_argument('bar', nargs='+', help='bar help')
>>> parser.print_help()
usage: PROG [options]

positional arguments:
 bar          bar help

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

description

help信息前的文字。

epilog

help信息之后的信息

>>> parser = argparse.ArgumentParser(
...     description='A foo that bars',
...     epilog="And that's how you'd foo a bar")
>>> parser.print_help()
usage: argparse.py [-h]

A foo that bars

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

And that's how you'd foo a bar

parents

由ArgumentParser对象组成的列表,它们的arguments选项会被包含到新ArgumentParser对象中。

>>> parent_parser = argparse.ArgumentParser(add_help=False)
>>> parent_parser.add_argument('--parent', type=int)

>>> foo_parser = argparse.ArgumentParser(parents=[parent_parser])
>>> foo_parser.add_argument('foo')
>>> foo_parser.parse_args(['--parent', '2', 'XXX'])
Namespace(foo='XXX', parent=2)

formatter_class

help信息输出的格式.

prefix_chars

参数前缀,默认为'-'

>>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='-+')
>>> parser.add_argument('+f')
>>> parser.add_argument('++bar')
>>> parser.parse_args('+f X ++bar Y'.split())
Namespace(bar='Y', f='X')

fromfile_prefix_chars

前缀字符,放在文件名之前

>>> with open('args.txt', 'w') as fp:
...    fp.write('-f\nbar')
>>> parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
>>> parser.add_argument('-f')
>>> parser.parse_args(['-f', 'foo', '@args.txt'])
Namespace(f='bar')

当参数过多时,可以将参数放到文件中读取,例子中parser.parse_args(['-f', 'foo', '@args.txt'])解析时会从文件args.txt读取,相当于 ['-f', 'foo', '-f', 'bar']。

argument_default

参数的全局默认值。例如,要禁止parse_args时的参数默认添加,我们可以:

>>> parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
>>> parser.add_argument('--foo')
>>> parser.add_argument('bar', nargs='?')
>>> parser.parse_args(['--foo', '1', 'BAR'])
Namespace(bar='BAR', foo='1')
>>> parser.parse_args()
Namespace()

当parser.parse_args()时不会自动解析foo和bar了。

conflict_handler

解决冲突的策略,默认情况下冲突会发生错误:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-f', '--foo', help='old foo help')
>>> parser.add_argument('--foo', help='new foo help')
Traceback (most recent call last):
 ..
ArgumentError: argument --foo: conflicting option string(s): --foo

我们可以设定冲突解决策略:

>>> parser = argparse.ArgumentParser(prog='PROG', conflict_handler='resolve')
>>> parser.add_argument('-f', '--foo', help='old foo help')
>>> parser.add_argument('--foo', help='new foo help')
>>> parser.print_help()
usage: PROG [-h] [-f FOO] [--foo FOO]

optional arguments:
 -h, --help  show this help message and exit
 -f FOO      old foo help
 --foo FOO   new foo help

add_help

设为False时,help信息里面不再显示-h --help信息。

方法add_argument 参数选项

add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])
>>> 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)')

name or flags

命令行参数名或者选项,如上面的address或者-p,--port.其中命令行参数如果没给定,且没有设置defualt,则出错。但是如果是选项的话,则设置为None,如果是多个参数(短参数和长参数)表示同一个意义的话,可用,隔开

一共有两种,位置参数和可选参数.

添加可选参数:

>>> parser.add_argument('-f', '--foo')

添加位置参数:

>>> parser.add_argument('bar')

parse_args()运行时,会用'-'来认证可选参数,剩下的即为位置参数。

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-f', '--foo')
>>> parser.add_argument('bar')
>>> parser.parse_args(['BAR'])
Namespace(bar='BAR', foo=None)
>>> parser.parse_args(['BAR', '--foo', 'FOO'])
Namespace(bar='BAR', foo='FOO')
>>> parser.parse_args(['--foo', 'FOO'])
usage: PROG [-h] [-f FOO] bar
PROG: error: too few arguments

解析时没有位置参数就会报错了。

action

默认为store

store_const,值存放在const中:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='store_const', const=42)
>>> parser.parse_args('--foo'.split())
Namespace(foo=42)

store_true和store_false,值存为True或False:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='store_true')
>>> parser.add_argument('--bar', action='store_false')
>>> parser.add_argument('--baz', action='store_false')
>>> parser.parse_args('--foo --bar'.split())
Namespace(bar=False, baz=True, foo=True)

append:存为列表

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='append')
>>> parser.parse_args('--foo 1 --foo 2'.split())
Namespace(foo=['1', '2'])

append_const:存为列表,会根据const关键参数进行添加:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--str', dest='types', action='append_const', const=str)
>>> parser.add_argument('--int', dest='types', action='append_const', const=int)
>>> parser.parse_args('--str --int'.split())
Namespace(types=[<type 'str'>, <type 'int'>])

count:统计参数出现的次数

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--verbose', '-v', action='count')
>>> parser.parse_args('-vvv'.split())
Namespace(verbose=3)

version:版本

>>> import argparse
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--version', action='version', version='%(prog)s 2.0')
>>> parser.parse_args(['--version'])
PROG 2.0

nargs

命令行参数的个数,一般使用通配符表示,其中,'?'表示只用一个,'*'表示0到多个,'+'表示至少一个

值可以为整数N(N个),*(任意多个),+(一个或更多)

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', nargs='*')
>>> parser.add_argument('--bar', nargs='*')
>>> parser.add_argument('baz', nargs='*')
>>> parser.parse_args('a b --foo x y --bar 1 2'.split())
Namespace(bar=['1', '2'], baz=['a', 'b'], foo=['x', 'y'])

值为?时,首先从命令行获得参数,若没有则从const获得,然后从default获得:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', nargs='?', const='c', default='d')
>>> parser.add_argument('bar', nargs='?', default='d')
>>> parser.parse_args('XX --foo YY'.split())
Namespace(bar='XX', foo='YY')
>>> parser.parse_args('XX --foo'.split())
Namespace(bar='XX', foo='c')
>>> parser.parse_args(''.split())
Namespace(bar='d', foo='d')

获取参数顺序:命令行-->const-->default

更常用的情况是允许参数为文件:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
...                     default=sys.stdin)
>>> parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),
...                     default=sys.stdout)
>>> parser.parse_args(['input.txt', 'output.txt'])
Namespace(infile=<open file 'input.txt', mode 'r' at 0x...>,
          outfile=<open file 'output.txt', mode 'w' at 0x...>)
>>> parser.parse_args([])
Namespace(infile=<open file '<stdin>', mode 'r' at 0x...>,
          outfile=<open file '<stdout>', mode 'w' at 0x...>)

const

保存一个常量

default

默认值,上面刚介绍过

choices

可供选择的值

>>> parser = argparse.ArgumentParser(prog='doors.py')
>>> parser.add_argument('door', type=int, choices=range(1, 4))
>>> print(parser.parse_args(['3']))
Namespace(door=3)
>>> parser.parse_args(['4'])
usage: doors.py [-h] {1,2,3}
doors.py: error: argument door: invalid choice: 4 (choose from 1, 2, 3)

type

参数的类型,默认是字符串string类型,还有float、int等类型

required

是否必选

desk

可作为参数名

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', dest='bar')
>>> parser.parse_args('--foo XXX'.split())
Namespace(bar='XXX')

help

和ArgumentParser方法中的参数作用相似,出现的场合也一致

解析参数的几种写法

最常见的空格分开:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-x')
>>> parser.add_argument('--foo')
>>> parser.parse_args('-x X'.split())
Namespace(foo=None, x='X')
>>> parser.parse_args('--foo FOO'.split())
Namespace(foo='FOO', x=None)

长选项用=分开

>>> parser.parse_args('--foo=FOO'.split())
Namespace(foo='FOO', x=None)

短选项可以写在一起:

>>> parser.parse_args('-xX'.split())
Namespace(foo=None, x='X')

parse_args()方法的返回值为namespace,可以用vars()内建函数化为字典:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> args = parser.parse_args(['--foo', 'BAR'])
>>> vars(args)
{'foo': 'BAR'}

例子

例子1:

import argparse

def parse_args():
    description = usage: %prog [options] poetry-file

This is the Slow Poetry Server, blocking edition.
Run it like this:

  python slowpoetry.py 

If you are in the base directory of the twisted-intro package,
you could run it like this:

  python blocking-server/slowpoetry.py poetry/ecstasy.txt

to serve up John Donne's Ecstasy, which I know you want to do.


    parser = argparse.ArgumentParser(description = description)
    
    help = The addresses to connect.
    parser.add_argument('addresses',nargs = '*',help = help)

    help = The filename to operate on.Default is poetry/ecstasy.txt
    parser.add_argument('filename',help=help)

    help = The port to listen on. Default to a random available port.
    parser.add_argument('-p',--port', type=int, help=help)

    help = The interface to listen on. Default is localhost.
    parser.add_argument('--iface', help=help, default='localhost')

    help = The number of seconds between sending bytes.
    parser.add_argument('--delay', type=float, help=help, default=.7)

    help = The number of bytes to send at a time.
    parser.add_argument('--bytes', type=int, help=help, default=10)

    args = parser.parse_args();
    return args

if __name__ == '__main__':
	args = parse_args()
	
	for address in args.addresses:
		print 'The address is : %s .' % address
	
	print 'The filename is : %s .' % args.filename
	print 'The port is : %d.' % args.port
	print 'The interface is : %s.' % args.iface
	print 'The number of seconds between sending bytes : %f'% args.delay
	print 'The number of bytes to send at a time : %d.' % args.bytes

例子2

有一道面试题:编写一个脚本main.py,使用方式如下:

main.py -u http://www.sohu.com -d 'a=1,b=2,c=3' -o /tmp/index.html

功能要求:打开-u指定的页面,将页面中所有的链接后面增加参数a=1&b=2&c=3(需要考虑链接中已经存在指定的参数的问题), 然后保存到-o指定的文件中。

import argparse
import urllib
from pyquery import PyQuery as pq
def getArgs():
	parse=argparse.ArgumentParser()
	parse.add_argument('-u',type=str)
	parse.add_argument('-d',type=str)
	parse.add_argument('-o',type=str)
	args=parse.parse_args()
	return vars(args)
def urlAddQuery(url,query):
	query=query.replace(',','&')  
	if '?' in url:
		return url.replace('?','?'+query+'&')
	else:
		return url+'?'+query
def getHref():
	args=getArgs()
	url=args['u']
	query=args['d'].strip("\'")
	fileName=args['o']
	doc=pq(url=url)
	with open(fileName,'w') as f:
		for a in doc('a'):
			a=pq(a)
			href=a.attr('href')
			if href:
				newurl=urlAddQuery(href,query)
				f.write(newurl+'\n')
if __name__=='__main__':
	getHref()
posted @ 2017-02-07 17:16  ccorz  阅读(12842)  评论(0编辑  收藏  举报