Ví dụ đối số đơn giản muốn: 1 đối số, 3 kết quả


529

Các tài liệu hướng dẫn cho các mô-đun python argparse , trong khi xuất sắc Tôi chắc chắn, là quá nhiều cho người mới bắt đầu não nhỏ bé của tôi để nắm bắt ngay bây giờ. Tôi không cần phải làm toán trên dòng lệnh hoặc can thiệp với các dòng định dạng trên màn hình hoặc thay đổi các ký tự tùy chọn. Tất cả những gì tôi muốn làm là "Nếu arg là A, hãy làm điều này, nếu B làm điều đó, nếu không có điều nào ở trên cho thấy sự giúp đỡ và bỏ cuộc" .


15
sau đó chỉ cần kiểm tra sys.argvđối số bạn muốn ...
JBernardo

10
Bao giờ cố gắng plac ? Thật dễ dàng để sử dụng trình bao bọc trên argparse với tài liệu tuyệt vời .
kirbyfan64sos

157
không phải bạn đó là tranh luận. nó đang cố gắng đưa bạn vào cuộc hành trình đến những vì sao và không quan tâm bạn đang đi đâu.
Florian Heigl

11
API "pythonic" điên rồ một lần nữa: /
mlvljr

69
Bless you matt wilkie, vì đã đứng lên cho bộ não người mới bắt đầu nhỏ bé ở khắp mọi nơi.
polka

Câu trả lời:


255

Sự hiểu biết của tôi về câu hỏi ban đầu là hai lần. Đầu tiên, về ví dụ đơn giản nhất có thể, tôi ngạc nhiên rằng tôi đã không thấy nó ở đây. Tất nhiên, để đơn giản, nó cũng hoạt động với rất ít năng lượng, nhưng nó có thể giúp bạn bắt đầu.

import argparse

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

if args.a == 'magic.name':
    print 'You nailed it!'

Nhưng đối số vị trí này là bắt buộc. Nếu bạn bỏ nó khi gọi chương trình này, bạn sẽ gặp lỗi về các đối số bị thiếu. Điều này dẫn tôi đến phần thứ hai của câu hỏi ban đầu. Matt Wilkie dường như muốn một đối số tùy chọn duy nhất mà không có nhãn được đặt tên (nhãn --option). Đề nghị của tôi sẽ là sửa đổi mã ở trên như sau:

...
parser.add_argument("a", nargs='?', default="check_string_for_empty")
...
if args.a == 'check_string_for_empty':
    print 'I can tell that no argument was given and I can deal with that here.'
elif args.a == 'magic.name':
    print 'You nailed it!'
else:
    print args.a

Có thể có một giải pháp thanh lịch hơn, nhưng điều này hoạt động và tối giản.


4
Sau một thời gian suy ngẫm, tôi kết luận câu hỏi này thực sự trả lời tốt nhất câu hỏi Q và câu hỏi tôi đang gặp phải vào thời điểm đó. Các câu trả lời xuất sắc khác đã thu được nhiều hơn đủ đại diện để chứng minh giá trị của họ và có thể cạnh tranh một chút. :-)
matt wilkie

@badnack: Đó là bất cứ điều gì bạn muốn, bất cứ điều gì 'a' đại diện. Nếu bạn mong đợi một đối số, ví dụ tên tệp, thì đó là tên được nhập dưới dạng tên tệp trên dòng lệnh. Sau đó, bạn có thể tự xử lý để xác định xem nó có tồn tại trong hệ thống tệp hay không, nhưng đó là một câu hỏi và trả lời khác.
mightypile 11/05/2015

363

Đây là cách tôi làm với argparse(với nhiều đối số):

parser = argparse.ArgumentParser(description='Description of your program')
parser.add_argument('-f','--foo', help='Description for foo argument', required=True)
parser.add_argument('-b','--bar', help='Description for bar argument', required=True)
args = vars(parser.parse_args())

args sẽ là một từ điển chứa các đối số:

if args['foo'] == 'Hello':
    # code here

if args['bar'] == 'World':
    # code here

Trong trường hợp của bạn chỉ cần thêm một đối số.


3
như đã đề cập trong bình luận của tôi cho câu trả lời khác, tôi muốn giữ định dạng trợ giúp tự động của argparse, nhưng dường như không có tùy chọn nào để có một đối số không được đặt tên (nhiều khả năng tôi không hiểu nó khi tôi nhìn thấy nó ), ví dụ: một người cần phải làm foo.py --action installhoặc foo.py --action removethay vì chỉ đơn giảnfoo.py install
matt wilkie

7
@mattwilkie Sau đó, bạn phải xác định một đối số vị trí như thế này: parser.add_argument('install', help='Install the app') (Lưu ý rằng bạn không thể xác định một đối số vị trí với required=True)
Diego Navarro

32
Là một người không thích tranh luận, câu trả lời này thực sự hữu ích vì tôi không biết tìm các lựa chọn ở đâu sau khi chúng được thông qua . Nói cách khác, tôi cần phải hiểu làm thế nào chính tả argsđược tạo ra như trên.
mrKelley

3
Sử dụng 'biểu mẫu ngắn' khi gọi chương trình trực tiếp từ dòng lệnh và 'biểu mẫu dài' khi bạn chạy chương trình / lệnh trong tập lệnh. Trong trường hợp đó, con người dễ đọc hơn với dạng dài và do đó dễ dàng tuân theo logic của mã / tập lệnh hơn.
ola

17
Cá nhân tôi thấy nó dễ dàng hơn để truy cập các đối số như args.fooargs.barthay vì cú pháp từ điển. Tất cả các cách đều tốt, nhưng args không thực sự là một từ điển mà là một argparse.Namespaceđối tượng.
Michael Mior

210

Các argparsetài liệu này là hợp lý tốt nhưng bỏ qua một vài chi tiết hữu ích có thể không rõ ràng. (@Diego Navarro đã đề cập đến một số điều này nhưng tôi sẽ cố gắng mở rộng câu trả lời của anh ấy một chút.) Cách sử dụng cơ bản như sau:

parser = argparse.ArgumentParser()
parser.add_argument('-f', '--my-foo', default='foobar')
parser.add_argument('-b', '--bar-value', default=3.14)
args = parser.parse_args()

Đối tượng bạn nhận được từ đó parse_args()là một đối tượng 'Không gian tên': Một đối tượng có các biến thành viên được đặt tên theo các đối số dòng lệnh của bạn. Đối Namespacetượng là cách bạn truy cập các đối số của mình và các giá trị được liên kết với chúng:

args = parser.parse_args()
print args.my_foo
print args.bar_value

(Lưu ý rằng argparsethay thế '-' trong tên đối số của bạn bằng dấu gạch dưới khi đặt tên biến.)

Trong nhiều tình huống, bạn có thể muốn sử dụng các đối số chỉ đơn giản là các cờ không có giá trị. Bạn có thể thêm những người trong argparse như thế này:

parser.add_argument('--foo', action='store_true')
parser.add_argument('--no-foo', action='store_false')

Ở trên sẽ tạo các biến có tên 'foo' với giá trị True và 'no_foo' với giá trị false, tương ứng:

if (args.foo):
    print "foo is true"

if (args.no_foo is False):
    print "nofoo is false"

Cũng lưu ý rằng bạn có thể sử dụng tùy chọn "bắt buộc" khi thêm đối số:

parser.add_argument('-o', '--output', required=True)

Theo cách đó, nếu bạn bỏ qua đối số này tại dòng lệnh argparsesẽ cho bạn biết nó bị thiếu và dừng thực thi tập lệnh của bạn.

Cuối cùng, lưu ý rằng có thể tạo cấu trúc chính tả cho các đối số của bạn bằng cách sử dụng varshàm, nếu điều đó làm cho cuộc sống của bạn dễ dàng hơn.

args = parser.parse_args()
argsdict = vars(args)
print argsdict['my_foo']
print argsdict['bar_value']

Như bạn có thể thấy, varstrả về một dict với tên đối số của bạn là khóa và giá trị của chúng là, er, giá trị.

Có rất nhiều lựa chọn và những điều bạn có thể làm, nhưng điều này sẽ bao gồm các tình huống sử dụng phổ biến, thiết yếu nhất.


3
Điểm của '-f'và là '-b'gì? Tại sao bạn không thể bỏ qua điều này?
dùng2763361

13
Nó khá thông thường khi có cả phiên bản 'dạng ngắn' (một dấu gạch ngang) và 'dạng dài' (hai dấu gạch ngang) cho mỗi tùy chọn thời gian chạy. Bạn sẽ thấy điều này, ví dụ, trong hầu hết mọi tiện ích Unix / Linux tiêu chuẩn; làm một man cphoặc man lsvà bạn sẽ thấy rằng nhiều lựa chọn có cả hai hương vị (ví dụ -f, --force). Có thể có nhiều lý do khác nhau tại sao mọi người thích cái này hay cái kia, nhưng trong mọi trường hợp, đó là tiêu chuẩn đẹp để cung cấp cả hai hình thức trong chương trình của bạn.
DMH

59

Matt đang hỏi về các tham số vị trí trong argparse và tôi đồng ý rằng tài liệu Python thiếu về khía cạnh này. Không có một ví dụ hoàn chỉnh nào trong ~ 20 trang lẻ hiển thị cả phân tích cú pháp và sử dụng các tham số vị trí .

Không có câu trả lời nào khác ở đây hiển thị một ví dụ hoàn chỉnh về các tham số vị trí, vì vậy, đây là một ví dụ hoàn chỉnh:

# tested with python 2.7.1
import argparse

parser = argparse.ArgumentParser(description="An argparse example")

parser.add_argument('action', help='The action to take (e.g. install, remove, etc.)')
parser.add_argument('foo-bar', help='Hyphens are cumbersome in positional arguments')

args = parser.parse_args()

if args.action == "install":
    print("You asked for installation")
else:
    print("You asked for something other than installation")

# The following do not work:
# print(args.foo-bar)
# print(args.foo_bar)

# But this works:
print(getattr(args, 'foo-bar'))

Điều khiến tôi thất vọng là argparse sẽ chuyển đổi đối số được đặt tên "--foo-bar" thành "foo_bar", nhưng một tham số vị trí có tên là "foo-bar" vẫn là "foo-bar", làm cho nó ít rõ ràng hơn sử dụng nó trong chương trình của bạn

Lưu ý hai dòng gần cuối ví dụ của tôi - cả hai dòng này sẽ không hoạt động để lấy giá trị của tham số vị trí foo-bar. Cái đầu tiên rõ ràng là sai (đó là một biểu thức số học args.foo trừ thanh), nhưng cái thứ hai cũng không hoạt động:

AttributeError: 'Namespace' object has no attribute 'foo_bar'

Nếu bạn muốn sử dụng foo-barthuộc tính, bạn phải sử dụng getattr, như đã thấy trong dòng cuối cùng của ví dụ của tôi. Điều điên rồ là nếu bạn cố gắng sử dụng dest=foo_barđể thay đổi tên thuộc tính thành thứ gì đó dễ truy cập hơn, bạn sẽ nhận được một thông báo lỗi thực sự kỳ lạ:

ValueError: dest supplied twice for positional argument

Dưới đây là cách ví dụ trên chạy:

$ python test.py
usage: test.py [-h] action foo-bar
test.py: error: too few arguments

$ python test.py -h
usage: test.py [-h] action foo-bar

An argparse example

positional arguments:
  action      The action to take (e.g. install, remove, etc.)
  foo-bar     Hyphens are cumbersome in positional arguments

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

$ python test.py install foo
You asked for installation
foo

5
nargs='?'là câu thần chú cho một "vị trí tùy chọn" theo stackoverflow.com/questions/4480075/iêu
MarkHu

Thực tế là một vị trí foo-barkhông được chuyển đổi thành foo_barđịa chỉ trong bug.python.org/su15125 .
hpaulj

2
Tôi nghĩ cách khắc phục dễ dàng hơn cho lỗi này là chỉ cần gọi đối số là "foo_bar" thay vì "foo-bar", sau đó print args.foo_barhoạt động. Vì đó là một đối số vị trí, bạn không phải chỉ định tên khi gọi tập lệnh, vì vậy nó không quan trọng đối với người dùng.
luator

@luator Bạn nói đúng, rất dễ để đổi tên đối số, nhưng tác giả của báo cáo lỗi đưa ra một trường hợp tốt rằng đây vẫn là một hành vi sai trái vì tải nhận thức không cần thiết. Khi sử dụng argparse, người ta phải tạm dừng và nhớ lại các quy ước đặt tên khác nhau cho các tùy chọn và đối số. Xem bug.python.org/msg164968 .
Đánh dấu E. Haase

1
@mehaase Tôi hoàn toàn đồng ý rằng đây là một lỗi sai nên được sửa. Tôi chỉ nghĩ đổi tên đối số là cách giải quyết dễ dàng và ít gây nhầm lẫn hơn là phải sử dụng getattr(nó cũng linh hoạt hơn vì nó cho phép bạn thay đổi đối số từ tùy chọn sang vị trí mà không phải thay đổi mã sử dụng giá trị).
luator

22

Một giới thiệu tóm tắt khác, lấy cảm hứng từ bài viết này .

import argparse

# define functions, classes, etc.

# executes when your script is called from the command-line
if __name__ == "__main__":

    parser = argparse.ArgumentParser()
    #
    # define each option with: parser.add_argument
    #
    args = parser.parse_args() # automatically looks at sys.argv
    #
    # access results with: args.argumentName
    #

Các đối số được xác định với sự kết hợp của các điều sau đây:

parser.add_argument( 'name', options... )              # positional argument
parser.add_argument( '-x', options... )                # single-char flag
parser.add_argument( '-x', '--long-name', options... ) # flag with long name

Các tùy chọn phổ biến là:

  • help : mô tả cho arg này khi --helpđược sử dụng.
  • default : giá trị mặc định nếu arg bị bỏ qua.
  • loại : nếu bạn mong đợi một floathoặc int(nếu không str).
  • mệnh : đặt một tên khác cho một lá cờ (ví dụ '-x', '--long-name', dest='longName').
    Lưu ý: theo mặc định --long-nameđược truy cập vớiargs.long_name
  • hành động : để xử lý đặc biệt các đối số nhất định
    • store_true, store_false: cho các đối số boolean
      '--foo', action='store_true' => args.foo == True
    • store_const: được sử dụng với tùy chọnconst
      '--foo', action='store_const', const=42 => args.foo == 42
    • count: cho các tùy chọn lặp đi lặp lại, như trong./myscript.py -vv
      '-v', action='count' => args.v == 2
    • append: cho các tùy chọn lặp đi lặp lại, như trong./myscript.py --foo 1 --foo 2
      '--foo', action='append' => args.foo == ['1', '2']
  • bắt buộc : nếu một cờ được yêu cầu, hoặc một đối số vị trí thì không.
  • nargs : cho một cờ để bắt N args
    ./myscript.py --foo a b => args.foo = ['a', 'b']
  • lựa chọn : để hạn chế các đầu vào có thể (chỉ định dưới dạng danh sách các chuỗi hoặc ints nếu type=int).

12

Lưu ý Hướng dẫn Argparse trong Python HOWTOs . Nó bắt đầu từ hầu hết các ví dụ cơ bản, như thế này:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
args = parser.parse_args()
print(args.square**2)

và tiến tới những cái ít cơ bản hơn.

Có một ví dụ với lựa chọn được xác định trước cho một tùy chọn, như những gì được hỏi:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
parser.add_argument("-v", "--verbosity", type=int, choices=[0, 1, 2],
                    help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
    print("the square of {} equals {}".format(args.square, answer))
elif args.verbosity == 1:
    print("{}^2 == {}".format(args.square, answer))
else:
    print(answer)

Thật tuyệt khi thấy rằng các tài liệu đã được cập nhật. Tôi đảm bảo với bạn đây không phải là trường hợp khi OP đăng câu hỏi 5 năm trước.
ntwrkguru

10

Đây là những gì tôi nghĩ ra trong dự án học tập của mình, chủ yếu nhờ vào @DMH ...

Mã trình diễn:

import argparse

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-f', '--flag', action='store_true', default=False)  # can 'store_false' for no-xxx flags
    parser.add_argument('-r', '--reqd', required=True)
    parser.add_argument('-o', '--opt', default='fallback')
    parser.add_argument('arg', nargs='*') # use '+' for 1 or more args (instead of 0 or more)
    parsed = parser.parse_args()
    # NOTE: args with '-' have it replaced with '_'
    print('Result:',  vars(parsed))
    print('parsed.reqd:', parsed.reqd)

if __name__ == "__main__":
    main()

Điều này có thể đã phát triển và có sẵn trực tuyến: lệnh-line.py

Kịch bản để cung cấp cho mã này một bài tập: lệnh-line-demo.sh


2
Cuối cùng, một ví dụ argparse có ý nghĩa
opentokix

5

Bạn cũng có thể sử dụng plac (một lớp bọc xung quanh argparse).

Như một phần thưởng, nó tạo ra các hướng dẫn trợ giúp gọn gàng - xem bên dưới.

Kịch bản ví dụ:

#!/usr/bin/env python3
def main(
    arg: ('Argument with two possible values', 'positional', None, None, ['A', 'B'])
):
    """General help for application"""
    if arg == 'A':
        print("Argument has value A")
    elif arg == 'B':
        print("Argument has value B")

if __name__ == '__main__':
    import plac
    plac.call(main)

Ví dụ đầu ra:

Không có đối số được cung cấp - example.py :

usage: example.py [-h] {A,B}
example.py: error: the following arguments are required: arg

Đối số bất ngờ được cung cấp - example.py C :

usage: example.py [-h] {A,B}
example.py: error: argument arg: invalid choice: 'C' (choose from 'A', 'B')

Đối số đúng được cung cấp - example.py A :

Argument has value A

Menu trợ giúp đầy đủ (được tạo tự động) - example.py -h :

usage: example.py [-h] {A,B}

General help for application

positional arguments:
  {A,B}       Argument with two possible values

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

Giải thích ngắn gọn:

Tên của đối số thường bằng với tên tham số ( arg).

Chú thích tuple sau argtham số có ý nghĩa như sau:

  • Mô tả ( Argument with two possible values)
  • Loại đối số - một trong 'cờ', 'tùy chọn' hoặc 'vị trí' ( positional)
  • Viết tắt ( None)
  • Loại giá trị đối số - ví dụ. float, chuỗi ( None)
  • Bộ lựa chọn bị hạn chế ( ['A', 'B'])

Tài liệu:

Để tìm hiểu thêm về việc sử dụng plac hãy xem tài liệu tuyệt vời của nó:

Vị trí: Phân tích dòng lệnh một cách dễ dàng


4

Để thêm vào những gì người khác đã nêu:

Tôi thường thích sử dụng tham số 'Dest' để chỉ định tên biến và sau đó sử dụng 'globalals (). Update ()' để đặt các biến đó trong không gian tên toàn cục.

Sử dụng:

$ python script.py -i "Hello, World!"

Mã số:

...
parser.add_argument('-i', '--input', ..., dest='inputted_variable',...)
globals().update(vars(parser.parse_args()))
...
print(inputted_variable) # Prints "Hello, World!"

argparseSử dụng nội bộ getattrsetattrđể truy cập các giá trị trong Không gian tên. Bằng cách đó, nó không bị làm phiền bởi destcác giá trị được hình thành kỳ lạ .
hpaulj

1

Một cách thực sự đơn giản để sử dụng argparse và sửa đổi các công tắc '-h' / '--help' để hiển thị các hướng dẫn trợ giúp mã cá nhân của riêng bạn là đặt trợ giúp mặc định thành Sai, bạn cũng có thể thêm bao nhiêu .add_argument tùy thích :

import argparse

parser = argparse.ArgumentParser(add_help=False)

parser.add_argument('-h', '--help', action='help',
                help='To run this script please provide two arguments')
parser.parse_args()

Chạy: python test.py -h

Đầu ra:

usage: test.py [-h]

optional arguments:
  -h, --help  To run this script please provide two arguments

-1

Câu trả lời đơn giản nhất!

PS người đã viết tài liệu của argparse là ngu ngốc

mã trăn:

import argparse
parser = argparse.ArgumentParser(description='')
parser.add_argument('--o_dct_fname',type=str)
parser.add_argument('--tp',type=str)
parser.add_argument('--new_res_set',type=int)
args = parser.parse_args()
o_dct_fname = args.o_dct_fname
tp = args.tp
new_res_set = args.new_res_set

mã chạy

python produce_result.py --o_dct_fname o_dct --tp father_child --new_res_set 1

Câu trả lời này không thêm bất cứ điều gì mới / khác với câu trả lời hiện có.
NVS Abhilash

Tôi là người rõ ràng nhất, nói chuyện là rẻ tiền, hiển thị mã
gouxute
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.