如何读取/处理命令行参数?


622

我原本是C程序员。我看到了许多花招和“技巧”来阅读许多不同的论点。

Python程序员可以通过哪些方式做到这一点?

有关


5
使用docopt(请参阅stackoverflow.com/a/14790373/116891上的 @ralbatross答案)。我已经尝试了其他所有方法,实际上,docopt是我以后将使用的唯一方法。
2013年

2
我认为没有唯一的最佳方法。argparse是标准功能。docopt非常优雅,但不在标准库中。为了非常轻松的轻量级使用,您可以使函数默认值为您处理comand行参数默认值
西蒙·希布斯

Answers:


455

标准库中的规范解决方案是argparsedocs):

这是一个例子:

from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument("-f", "--file", dest="filename",
                    help="write report to FILE", metavar="FILE")
parser.add_argument("-q", "--quiet",
                    action="store_false", dest="verbose", default=True,
                    help="don't print status messages to stdout")

args = parser.parse_args()

argparse 支持(除其他外):

  • 任意顺序的多个选项。
  • 短期和长期选择。
  • 默认值。
  • 生成使用帮助消息。

27
是的,这些是最好的。由于它们是标准库的一部分,因此可以确保它们将可用并且易于使用。optparse特别强大且简单。
巴里·沃克

4
optparse是最好的之一;getopt是旧的,真的应该被认为已弃用。
jemfinch

12
在这一点上(12/2011),现在认为argparse比optparse更好,是吗?
oob

54
Python文档建议使用argparse而不是optparse。
EarthmeL12年

7
由于optparse已弃用,问题的提问者不再是堆栈溢出的成员,这是一个高度可见的问题的可接受答案-请考虑完全重写示例代码以使用stdlib argparse代替。
WIM

548
import sys

print("\n".join(sys.argv))

sys.argv 是一个列表,其中包含在命令行上传递给脚本的所有参数。

基本上,

import sys
print(sys.argv[1:])

83
对于非常简单的东西,这是要走的路,尽管您可能只想使用sys.argv[1:](避免使用脚本名称)。
熊加米奥夫

128

出于这些原因,只是为了使argparse传福音就更好了..本质上:

(从链接复制)

  • argparse模块可以处理位置和可选参数,而optparse仅可以处理可选参数

  • argparse对您的命令行界面应该是什么样的并不教条-支持-file或/ file之类的选项,以及必需的选项。Optparse拒绝支持这些功能,而是偏向于纯度而不是实用性

  • argparse会生成更多有用的用法消息,包括根据您的参数确定的命令行用法,以及有关位置参数和可选参数的帮助消息。optparse模块需要您编写自己的用法字符串,并且无法显示位置参数的帮助。

  • argparse支持消耗可变数量的命令行args的操作,而optparse要求事先知道确切数量的参数(例如1、2或3)

  • argparse支持分派到子命令allow_interspersed_args的解析器,而optparse需要手动设置 和执行解析器分派

和我个人最喜欢的:

  • argparse允许add_argument() 使用简单的可调用对象来指定类型和操作参数,而optparse则需要侵入类属性,例如 STORE_ACTIONSCHECK_METHODS进行正确的参数检查。

27
从2.7和3.2开始,这已成为标准Python的一部分:)
jpswain 2010年

什么是“可选参数”?您说他们在选择。我以为它们是可能提供或可能不提供的参数,但是您说它们是optparse的同时继续说“ optparse要求事先知道确切数量的参数”。因此,要么您对“可选参数”的定义与我的想法有所不同,要么您的答案与自身不一致。
ArtOfWarfare 2014年

1
只是一个麻烦:argparse文档也非常疯狂,非常复杂。对于“如何使命令行参数采用单个值以及如何访问该值”,您无法获得简单的答案。</
gripe

2
@osman这个关于argparse的柔和教程可能会有所帮助...
lifebalance

2
@ArtOfWarfare在此上下文中的“可选参数”大概意味着用类似选项的参数(例如-f或)指定的参数--foo,而“事先知道确切数量的参数”大概意味着没有任何前面的选项标志的位置参数。
mtraceur '18

67

还有argparsestdlib模块stdlib模块上的“改进” optparse)。argparse简介中的示例:

# script.py
import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'integers', metavar='int', type=int, choices=range(10),
         nargs='+', help='an integer in the range 0..9')
    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))

用法:

$ script.py 1 2 3 4
4

$ script.py --sum 1 2 3 4
10

1
它只是复制和粘贴
blitu12345 '18

3
在发布我的答案时,@ blitu12345没有其他答案以任何方式提及argparse。该模块本身不在stdlib中¶您对文档中的代码示例有什么看法?您为什么认为有必要提出自己的示例,而不是模块作者提供的示例?而且我不喜欢仅链接的答案(我并不孤单)。
jfs

1
来到这里的人们已经知道文档中的内容,这里只是为了进一步清除该主题。我的情况也是如此,但我真正发现的是原始文档的副本和粘贴。和平!
blitu12345

2
“人民来到这里已经有文件在一念什么” -我高度怀疑assumtion。不知何故。
sjas

49

一种方法是使用sys.argv。这将打印脚本名称作为第一个参数以及传递给它的所有其他参数。

import sys

for arg in sys.argv:
    print arg

49

docopt库是真的光滑。它从应用程序的用法字符串中构建一个参数dict。

例如来自docopt自述文件:

"""Naval Fate.

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='Naval Fate 2.0')
    print(arguments)

4
这已迅速成为我最喜欢的方式。它是字符串分析,因此有点脆弱,但是它在一处都很脆弱,您可以在try.docopt.org上预览逻辑。可选和互斥的论点以一种非常优雅的方式完成。
gvoysey's

4
我非常希望看到naval_fate.py的其余代码
John Lawrence

48

如果您需要快速但不太灵活的东西

main.py:

import sys

first_name = sys.argv[1]
last_name = sys.argv[2]
print("Hello " + first_name + " " + last_name)

然后跑 python main.py James Smith

产生以下输出:

你好詹姆斯史密斯


更现实的用法是python main.py "James Smith"这使James Smithsys.argv[1]和产生IndexError,当您尝试使用不存在的sys.argv[2]。引用行为在某种程度上取决于您从中运行Python的平台和外壳。
Tripleee

10
我不同意我的用法不太现实。假装您的程序需要知道一个人的确切名字和姓氏,才能在一个人可以拥有多个名字和姓氏的企业中运行脚本。如果詹姆斯·史密斯(James Smith)将约瑟夫(Joseph)作为额外的姓氏或姓氏,那么如果您这样做,如何区分约瑟夫(Joseph)是一个额外的姓氏或姓氏python main.py "James Joseph Smith"?如果您担心索引超出范围,则可以检查提供的参数数量。无论是否现实,我的示例都显示了如何处理多个参数。
肯特·芒特

1
所有其他答案都用于绘制月球登陆任务。我只是在使用gmail-trash-msg.py MessageID。此答案直接表明MessageID已传递了测试参数sys.argv[1]
WinEunuuchs2Unix

26
#set default args as -h , if no args:
if len(sys.argv) == 1: sys.argv[1:] = ["-h"]

19

我自己使用optparse,但真的很喜欢Simon Willison在他最近引入的optfunc库中的发展方向。它的工作原理是:

“对函数定义(包括其参数及其默认值)进行自省,并使用其来构建命令行参数解析器。”

因此,例如,此函数定义:

def geocode(s, api_key='', geocoder='google', list_geocoders=False):

变成以下optparse帮助文本:

    Options:
      -h, --help            show this help message and exit
      -l, --list-geocoders
      -a API_KEY, --api-key=API_KEY
      -g GEOCODER, --geocoder=GEOCODER

8

我喜欢stdlib中的getopt,例如:

try:
    opts, args = getopt.getopt(sys.argv[1:], 'h', ['help'])
except getopt.GetoptError, err: 
    usage(err)

for opt, arg in opts:
    if opt in ('-h', '--help'): 
        usage()

if len(args) != 1:
    usage("specify thing...")

最近,我一直在包装类似的东西,以使事情变得不太冗长(例如,使“ -h”隐式)。




5
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))

Assuming the Python code above is saved into a file called prog.py
$ python prog.py -h

Ref-link: https://docs.python.org/3.3/library/argparse.html


4

我建议将docopt看作是其他替代品的简单替代方案。

docopt是一个新项目,可以通过解析--help使用情况消息来工作,而不是要求您自己实现一切。您只需要将使用情况消息以POSIX格式输入即可。


4

另一个选择是argh。它基于argparse构建,并允许您编写如下内容:

import argh

# declaring:

def echo(text):
    "Returns given word as is."
    return text

def greet(name, greeting='Hello'):
    "Greets the user with given name. The greeting is customizable."
    return greeting + ', ' + name

# assembling:

parser = argh.ArghParser()
parser.add_commands([echo, greet])

# dispatching:

if __name__ == '__main__':
    parser.dispatch()

它会自动生成帮助,等等,您可以使用装饰器提供有关arg解析工作方式的额外指导。


这是最好的解决方案。使用argh比其他库或使用起来容易sys
Juanjo Salvador

我想喜欢,argh但它并不特别适合您最希望不要有带有子命令的命令的场景。
Tripleee

1
@tripleee YMMV,但是我发现,与库本身相比,这更多是文档方面的缺陷。def frobnicate_spleches(...)定义一个可以执行脚本所执行的功能,然后if __name__ == '__main__': argh.dispatch_command(frobnicate_spleches)在文件末尾执行的功能似乎是完全可行的。
圆形废墟

0

我的解决方案是entrypoint2。例:

from entrypoint2 import entrypoint
@entrypoint
def add(file, quiet=True): 
    ''' This function writes report.

    :param file: write report to FILE
    :param quiet: don't print status messages to stdout
    '''
    print file,quiet

帮助文字:

usage: report.py [-h] [-q] [--debug] file

This function writes report.

positional arguments:
  file         write report to FILE

optional arguments:
  -h, --help   show this help message and exit
  -q, --quiet  don't print status messages to stdout
  --debug      set logging level to DEBUG
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.