ChatGPT解决这个技术问题 Extra ChatGPT

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

我原本是一名 C 程序员。我已经看到了许多技巧和“黑客”来阅读许多不同的论点。

Python 程序员有哪些方法可以做到这一点?

有关的

获取/解析传递给 Python 脚本的命令行参数的最佳方法是什么?

实现“[command] [action] [parameter]”风格的命令行界面?

如何在 Python 中处理命令行参数?

如何使用 Python 的 optparse 格式化位置参数帮助?

使用 docopt(请参阅 stackoverflow.com/a/14790373/116891 处的@ralbatross 答案)。我已经尝试过所有其他方式,而且真的,docopt 是我以后唯一会使用的方式。
我认为没有一种最好的方法。 argparse 是标准且功能强大的。 docopt 非常优雅,但不在标准库中。为了非常轻松的轻量级使用,您可以make function default values handle comand line argument defaults for you

T
Timur Shtatland
import sys

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

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

基本上,

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

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

标准库中的规范解决方案是 argparse (docs):

这是一个例子:

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 支持(除其他外):

任何顺序的多个选项。

短期和长期的选择。

默认值。

生成使用帮助消息。


是的,这些是最好的。由于它们是标准库的一部分,因此您可以确保它们可用并且易于使用。特别是 optparse 功能强大且简单。
optparse 是最好的之一; getopt 很旧,确实应该被视为已弃用。
在这一点上(12/2011),argparse 现在被认为是比 optparse 更好的选择,对吗?
Python 文档建议使用 argparse 而不是 optparse。
由于 optparse 已被弃用,问题的提问者不再是堆栈溢出的成员,这是一个高度可见的问题的公认答案 - 请考虑完全重写您的示例代码以改用 stdlib argparse
S
Silfheed

只是为了 argparse 而传福音,这对 these 的原因更好。本质上:

(从链接复制)

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

argparse 对你的命令行界面应该是什么样子不是教条主义的 - 支持 -file 或 /file 之类的选项,以及必需的选项。 Optparse 拒绝支持这些功能,更喜欢纯粹而不是实用性

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

argparse 支持使用可变数量的命令行参数的操作,而 optparse 要求提前知道参数的确切数量(例如 1、2 或 3)

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

还有我个人最喜欢的:

argparse 允许使用简单的可调用对象指定 add_argument() 的类型和操作参数,而 optparse 需要破解类属性,如 STORE_ACTIONS 或 CHECK_METHODS 以获得正确的参数检查


从 2.7 和 3.2 开始,这现在是标准 Python 的一部分 :)
什么是“可选参数”?你说他们在 optparse 中。我认为它们是可能提供也可能不提供的参数,但您说它们在 optparse 中,同时继续说“optparse 要求提前知道参数的确切数量”。因此,要么您对“可选参数”的定义与我的想法不同,要么您的答案与自己不一致。
只是一个抱怨:argparse 文档也非常复杂。对于“如何使命令行参数接受单个值,以及如何访问该值”,您无法得到简单的答案。
@osman 这个关于 argparse 的温柔 tutorial 可能会有所帮助......
@ArtOfWarfare 在此上下文中的“可选参数”可能是指使用类似选项的参数(例如 -f--foo)指定的参数,而“提前知道参数的确切数量”可能是指在没有任何前面的选项标志的情况下给出的位置参数。
j
jfs

还有 argparse stdlib module(stdlib 的 optparse 模块上的“改进”)。 the introduction to 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

它只是一个复制和粘贴
@blitu12345 在发布我的答案时,没有其他答案以任何方式提及 argparse。模块本身不在标准库中¶你对文档中的代码示例有什么看法?为什么你认为有必要拿出你自己的例子而不是模块作者提供的例子?而且我不喜欢仅链接的答案(我并不孤单)。
来到这里的人们已经对文档中的内容有所了解,并且将在这里只是为了进一步了解该主题。我的情况也是如此,但我在这里真正找到的是原始文档的复制和粘贴。和平!
“来到这里的人们已经知道文档中的内容” - 我非常怀疑这个假设。不知何故。
K
Kent Munthe Caspersen

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

主要.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 Smith 放入 sys.argv[1] 并在您尝试使用不存在的 sys.argv[2] 时产生 IndexError。引用行为在一定程度上取决于您从哪个平台和 shell 运行 Python。
我不同意我的用法不太现实。假设您的程序需要知道一个人的确切名字和姓氏才能在人们可以有多个名字和姓氏的企业中运行脚本?如果 James Smith 将 Joseph 作为额外的名字或姓氏,如果您只使用 python main.py "James Joseph Smith",如何区分 Joseph 是额外的名字还是姓氏?如果您担心索引超出范围,可以添加对提供的参数数量的检查。不管是否不太现实,我的示例展示了如何处理多个参数。
所有其他答案都是为了策划登月任务。我只是简单地使用 gmail-trash-msg.py MessageID。这个答案是直接测试 MessageID 参数已在 sys.argv[1] 中传递。
P
Peter Mortensen

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

import sys

for arg in sys.argv:
    print arg

r
ralbatross

docopt 库非常漂亮。它从您的应用程序的使用字符串构建一个参数字典。

例如来自 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)

这已迅速成为我最喜欢的方式。它是字符串解析,所以有点脆弱,但它很脆弱all in one place,您可以在 try.docopt.org 预览您的逻辑。可选的和互斥的参数以一种非常优雅的方式完成。
我迫切希望看到 naval_fate.py 的其余代码
t
the Tin Man
#set default args as -h , if no args:
if len(sys.argv) == 1: sys.argv[1:] = ["-h"]

V
Van Gale

我自己使用 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

P
Peter Ericson

我喜欢 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”隐含)。


t
tverrbjelke

如您所见 optparse“optparse 模块已弃用,不会进一步开发;开发将继续使用 argparse 模块。”


R
Ryne Everett

Pocoo 的 click 更直观,需要的样板更少,并且至少与 argparse 一样强大。

到目前为止,我遇到的唯一弱点是您无法对帮助页面进行太多自定义,但这通常不是必需的,如果需要,docopt 似乎是明确的选择。


J
JON
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

M
Mufasa

您可能对我编写的一个 Python 小模块感兴趣,该模块可以更轻松地处理命令行参数(开源且免费使用)-Commando


已经有另一个名为 Commando 的命令行解析模块:github.com/lakshmivyas/commando。它使用装饰器包装 argparse。
蟒蛇和轮子的再发明
c
circular-ruin

另一个选项是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-parsing 应该如何工作的额外指导。


这是最好的解决方案。使用 argh 比使用其他库或使用 sys 更容易。
我想喜欢 argh,但它并不是特别适合您最希望没有带有子命令的命令的场景。
@tripleee YMMV,但我发现这更多的是文档中的缺陷,而不是库本身。让 def frobnicate_spleches(...) 定义一个函数来执行您的脚本所做的任何事情,然后在文件末尾执行 if __name__ == '__main__': argh.dispatch_command(frobnicate_spleches) 似乎是完全可行的。
D
David C. Bishop

我建议将 docopt 视为其他这些的简单替代方案。

docopt 是一个新项目,它通过解析您的 --help 使用消息而不是要求您自己实现所有内容来工作。您只需要将您的使用信息以 POSIX 格式输入。


V
Volodymyr Boiko

同样使用 python3,您可能会发现使用 Extended Iterable Unpacking 来处理可选的位置参数很方便,而无需额外的依赖:

try:
   _, arg1, arg2, arg3, *_ = sys.argv + [None] * 2
except ValueError:
   print("Not enough arguments", file=sys.stderr) # unhandled exception traceback is meaningful enough also
   exit(-1)

上面的 argv 解包使 arg2arg3 “可选” - 如果它们未在 argv 中指定,它们将为 None,而如果未指定第一个,则 ValueError 将是你的:

Traceback (most recent call last):
  File "test.py", line 3, in <module>
    _, arg1, arg2, arg3, *_ = sys.argv + [None] * 2
ValueError: not enough values to unpack (expected at least 4, got 3)

p
ponty

我的解决方案是 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

S
SimCop07
import sys

# Command line arguments are stored into sys.argv
# print(sys.argv[1:])

# I used the slice [1:] to print all the elements except the first
# This because the first element of sys.argv is the program name
# So the first argument is sys.argv[1], the second is sys.argv[2] ecc

print("File name: " + sys.argv[0])
print("Arguments:")
for i in sys.argv[1:]:
    print(i)

让我们将此文件命名为 command_line.py 并运行它:

C:\Users\simone> python command_line.py arg1 arg2 arg3 ecc
File name: command_line.py
Arguments:
arg1
arg2
arg3
ecc

现在让我们编写一个简单的程序 sum.py

import sys

try:
    print(sum(map(float, sys.argv[1:])))
except:
    print("An error has occurred")

结果:

C:\Users\simone> python sum.py 10 4 6 3
23

H
Hermano Mclintock

这处理简单的开关,带有可选替代标志的值开关。

import sys

# [IN] argv - array of args
# [IN] switch - switch to seek
# [IN] val - expecting value
# [IN] alt - switch alternative
# returns value or True if val not expected
def parse_cmd(argv,switch,val=None,alt=None):
    for idx, x in enumerate(argv):
        if x == switch or x == alt:
            if val:
                if len(argv) > (idx+1):            
                    if not argv[idx+1].startswith('-'):
                        return argv[idx+1]
            else:
                return True

//expecting a value for -i
i = parse_cmd(sys.argv[1:],"-i", True, "--input")

//no value needed for -p
p = parse_cmd(sys.argv[1:],"-p")

L
Lawrence Rich

我们的一些生物技术客户最近提出了这两个问题:

我们如何将 Python 脚本作为命令执行?

当 Python 脚本作为命令执行时,我们如何将输入值传递给它?

我在下面包含了一个 Python 脚本,我相信它可以回答这两个问题。假设以下 Python 脚本保存在文件 test.py 中:

#
#----------------------------------------------------------------------
#
# file name: test.py
#
# input values: data  - location of data to be processed
#               date  - date data were delivered for processing
#               study - name of the study where data originated
#               logs  - location where log files should be written 
#
# macOS usage: 
#
#   python3 test.py "/Users/lawrence/data" "20220518" "XYZ123" "/Users/lawrence/logs"
#
# Windows usage: 
#
#   python test.py "D:\data" "20220518" "XYZ123" "D:\logs"
#
#----------------------------------------------------------------------
#
# import needed modules...
#
import sys
import datetime

def main(argv):

   #
   # print message that process is starting...
   #
   print("test process starting at", datetime.datetime.now().strftime("%Y%m%d %H:%M"))

   #
   # set local values from input values...
   #
   data = sys.argv[1]
   date = sys.argv[2]
   study = sys.argv[3]
   logs = sys.argv[4]

   #
   # print input arguments...
   #
   print("data value is", data)
   print("date value is", date)
   print("study value is", study)
   print("logs value is", logs)

   #
   # print message that process is ending...
   #
   print("test process ending at", datetime.datetime.now().strftime("%Y%m%d %H:%M"))

#
# call main() to begin processing...
#

if __name__ == '__main__':

   main(sys.argv)

该脚本可以在 macOS 计算机上的终端 shell 中执行,如下所示,结果将打印到标准输出(确保当前目录包含 test.py 文件):

$ python3 test.py "/Users/lawrence/data" "20220518" "XYZ123" "/Users/lawrence/logs"
test process starting at 20220518 16:51
data value is /Users/lawrence/data
date value is 20220518
study value is XYZ123
logs value is /Users/lawrence/logs
test process ending at 20220518 16:51

该脚本也可以在 Windows 计算机上的命令提示符中执行,如下所示,结果将打印到标准输出(确保当前目录包含 test.py 文件):

D:\scripts>python test.py "D:\data" "20220518" "XYZ123" "D:\logs"
test process starting at 20220518 17:20
data value is D:\data
date value is 20220518
study value is XYZ123
logs value is D:\logs
test process ending at 20220518 17:20

该脚本回答了上面提出的两个问题,并且是开发将作为具有输入值的命令执行的脚本的良好起点。