Contoh argparse sederhana yang diinginkan: 1 argumen, 3 hasil

529

The dokumentasi untuk modul python argparse , sementara sangat baik saya yakin, terlalu banyak untuk otak pemula kecil saya untuk memahami sekarang. Saya tidak perlu melakukan matematika di baris perintah atau campur tangan dengan memformat garis di layar atau mengubah karakter opsi. Yang ingin saya lakukan adalah "Jika arg adalah A, lakukan ini, jika B melakukan itu, jika tidak ada yang di atas menunjukkan bantuan dan berhenti" .

matt wilkie
sumber
15
maka cukup periksa sys.argvargumen yang Anda inginkan ...
JBernardo
10
Pernah mencoba plac ? Ini adalah pembungkus argparse yang mudah digunakan dengan dokumentasi yang bagus .
kirbyfan64sos
157
ini bukan kamu. itu argparse. itu mencoba membawa Anda dalam perjalanan ke bintang-bintang dan tidak peduli ke mana Anda pergi.
Florian Heigl
11
Gila "pythonic" API lagi: /
mlvljr
69
Diberkatilah matt wilkie, karena membela otak kecil pemula di mana-mana.
polka

Jawaban:

255

Pemahaman saya tentang pertanyaan asli ada dua. Pertama, dalam hal contoh argparse yang paling sederhana, saya terkejut bahwa saya belum melihatnya di sini. Tentu saja, untuk menjadi sangat sederhana, itu semua di atas kepala dengan sedikit daya, tetapi itu mungkin bisa Anda mulai.

import argparse

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

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

Tetapi argumen posisi ini sekarang diperlukan. Jika Anda membiarkannya ketika menjalankan program ini, Anda akan mendapatkan kesalahan tentang argumen yang hilang. Ini membawa saya ke bagian kedua dari pertanyaan awal. Matt Wilkie tampaknya menginginkan argumen opsional tunggal tanpa label bernama (label --option). Saran saya adalah memodifikasi kode di atas sebagai berikut:

...
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

Mungkin ada solusi yang lebih elegan, tetapi ini bekerja dan minimalis.

mungkin
sumber
4
Setelah beberapa waktu merenung, saya menyimpulkan pertanyaan ini sebenarnya jawaban terbaik Q seperti yang ditanyakan dan kesulitan yang saya alami pada saat itu. Jawaban luar biasa lainnya telah mengumpulkan lebih dari cukup perwakilan untuk membuktikan nilai mereka dan dapat bertahan dalam kompetisi kecil. :-)
matt wilkie
@badnack: Ini apa pun yang Anda inginkan, apa pun yang mewakili 'a'. Jika Anda mengharapkan satu argumen, nama file misalnya, itu adalah apa yang dimasukkan sebagai nama file pada baris perintah. Anda kemudian dapat melakukan pemrosesan Anda sendiri untuk menentukan apakah itu ada di sistem file, tapi itu adalah T&J lain.
mayypile
363

Inilah cara saya melakukannya argparse(dengan beberapa argumen):

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 akan menjadi kamus yang berisi argumen:

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

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

Dalam kasus Anda cukup tambahkan hanya satu argumen.

Diego Navarro
sumber
3
seperti yang disebutkan dalam komentar saya untuk jawaban yang lain, saya ingin tetap menggunakan format bantuan otomatis argparse, tetapi sepertinya tidak ada pilihan untuk memiliki argumen yang tidak dikenal (kemungkinan besar saya hanya tidak memahaminya ketika saya melihatnya) ), mis. seseorang perlu melakukan foo.py --action installatau foo.py --action removebukannya hanyafoo.py install
matt wilkie
7
@mattwilkie Maka Anda harus mendefinisikan argumen posisi seperti ini: parser.add_argument('install', help='Install the app') (Perhatikan Anda tidak dapat mendefinisikan argumen posisi required=True)
Diego Navarro
32
Sebagai noob untuk berdebat, jawaban ini sangat membantu karena saya tidak tahu di mana menemukan opsi setelah mereka disahkan . Dengan kata lain, saya perlu memahami bagaimana argsdikt dibuat seperti di atas.
mrKelley
3
Gunakan 'formulir singkat' saat memanggil program langsung dari baris perintah dan 'formulir panjang' ketika Anda menjalankan program / perintah dalam skrip. Dalam hal ini lebih dapat dibaca manusia dengan bentuk panjang dan dengan demikian lebih mudah untuk mengikuti logika kode / skrip.
ola
17
Secara pribadi saya merasa bersih untuk argumen akses sebagai args.foodan args.barbukannya sintaks kamus. Yang manapun tentu saja baik-baik saja, tetapi args sebenarnya bukan sebuah kamus tetapi sebuah argparse.Namespaceobjek.
Michael Mior
210

The argparsedokumentasi cukup baik tapi daun keluar beberapa detail yang berguna yang mungkin tidak jelas. (@Diego Navarro sudah menyebutkan beberapa hal ini tetapi saya akan mencoba sedikit memperluas jawabannya.) Penggunaan dasar adalah sebagai berikut:

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

Objek tempat Anda kembali parse_args()adalah objek 'Namespace': Objek yang variabel anggotanya dinamai menurut argumen baris perintah Anda. The Namespaceobjek adalah bagaimana Anda mengakses argumen Anda dan nilai-nilai yang terkait dengan mereka:

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

(Catatan yang argparsemenggantikan '-' dalam nama argumen Anda dengan garis bawah saat menamai variabel.)

Dalam banyak situasi Anda mungkin ingin menggunakan argumen hanya sebagai flag yang tidak memiliki nilai. Anda dapat menambahkannya dalam argparse seperti ini:

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

Di atas akan membuat variabel bernama 'foo' dengan nilai True, dan 'no_foo' dengan nilai False, masing-masing:

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

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

Perhatikan juga bahwa Anda dapat menggunakan opsi "wajib" saat menambahkan argumen:

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

Dengan begitu, jika Anda menghilangkan argumen ini di baris perintah argparseakan memberi tahu Anda ada yang hilang dan menghentikan eksekusi skrip Anda.

Akhirnya, perhatikan bahwa membuat struktur dict argumen Anda menggunakan varsfungsi, jika itu membuat hidup Anda lebih mudah.

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

Seperti yang Anda lihat, varsmengembalikan dikt dengan nama argumen Anda sebagai kunci dan nilainya sebagai, eh, nilai.

Ada banyak opsi dan hal lain yang dapat Anda lakukan, tetapi ini harus mencakup skenario penggunaan yang paling esensial dan umum.

DMH
sumber
3
Apa gunanya '-f'dan '-b'? Mengapa Anda tidak bisa menghilangkan ini?
user2763361
13
Cukup konvensional untuk memiliki versi 'short form' (satu dash) dan 'long form' (dua dash) untuk setiap opsi runtime. Anda akan melihat ini, misalnya, di hampir setiap utilitas standar Unix / Linux; lakukan man cpatau man lsdan Anda akan menemukan bahwa banyak pilihan datang dalam kedua rasa (misalnya -f, --force). Mungkin ada berbagai alasan mengapa orang lebih suka satu atau yang lain, tetapi dalam hal apa pun itu cukup standar untuk membuat kedua bentuk tersedia di program Anda.
DMH
59

Matt bertanya tentang parameter posisi dalam argparse, dan saya setuju bahwa dokumentasi Python kurang pada aspek ini. Tidak ada satu pun, contoh lengkap dalam ~ 20 halaman ganjil yang menunjukkan parsing dan menggunakan parameter posisi .

Tidak ada jawaban lain di sini yang menunjukkan contoh lengkap parameter posisi, jadi, inilah contoh lengkapnya:

# 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'))

Hal yang mengusir saya adalah bahwa argparse akan mengubah argumen bernama "--foo-bar" menjadi "foo_bar", tetapi parameter posisi bernama "foo-bar" tetap sebagai "foo-bar", membuatnya menjadi kurang jelas bagaimana cara gunakan dalam program Anda.

Perhatikan dua baris di dekat akhir contoh saya - tak satu pun dari mereka akan bekerja untuk mendapatkan nilai param posisi posisi foo-bar. Yang pertama jelas salah (ini adalah ekspresi aritmatika args.foo minus bar), tetapi yang kedua tidak berfungsi:

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

Jika Anda ingin menggunakan foo-baratribut, Anda harus menggunakan getattr, seperti yang terlihat pada baris terakhir dari contoh saya. Yang gila adalah bahwa jika Anda mencoba menggunakan dest=foo_baruntuk mengubah nama properti menjadi sesuatu yang lebih mudah diakses, Anda akan mendapatkan pesan kesalahan yang sangat aneh:

ValueError: dest supplied twice for positional argument

Begini cara contoh di atas berjalan:

$ 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
Mark E. Haase
sumber
5
nargs='?'adalah mantra untuk "posisi opsional" sesuai stackoverflow.com/questions/4480075/...
MarkHu
Fakta bahwa suatu posisi foo-bartidak ditransformasikan ke foo_bardibahas dalam bugs.python.org/issue15125 .
hpaulj
2
Saya pikir solusi yang lebih mudah untuk bug ini adalah dengan hanya memanggil argumen "foo_bar" daripada "foo-bar", kemudian print args.foo_barbekerja. Karena ini adalah argumen posisi Anda tidak perlu menentukan nama saat memanggil skrip, sehingga tidak masalah bagi pengguna.
luator
@ luator Anda benar, mudah untuk mengubah nama argumen, tetapi penulis laporan bug membuat alasan yang baik bahwa ini masih salah karena beban kognitif yang tidak perlu. Saat menggunakan argparse, seseorang harus menghentikan sebentar dan mengingat konvensi penamaan yang berbeda untuk opsi dan argumen. Lihat bugs.python.org/msg164968 .
Mark E. Haase
1
@mease saya benar-benar setuju bahwa ini adalah kesalahan yang harus diperbaiki. Saya hanya berpikir mengubah nama argumen adalah solusi yang lebih mudah dan tidak membingungkan daripada harus menggunakan getattr(itu juga lebih fleksibel karena memungkinkan Anda untuk mengubah argumen dari opsional ke posisi tanpa harus mengubah kode yang menggunakan nilai).
luator
22

Pengantar ringkasan lain, terinspirasi oleh posting ini .

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
    #

Argumen didefinisikan dengan kombinasi dari yang berikut:

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

Pilihan umum adalah:

  • help : deskripsi untuk arg ini ketika --helpdigunakan.
  • default : nilai default jika arg dihilangkan.
  • ketik : jika Anda mengharapkan a floatatau int(sebaliknya str).
  • dest : berikan nama yang berbeda ke bendera (mis '-x', '--long-name', dest='longName'.).
    Catatan: secara default --long-namediakses denganargs.long_name
  • aksi : untuk penanganan khusus argumen tertentu
    • store_true, store_false: untuk boolean args
      '--foo', action='store_true' => args.foo == True
    • store_const: untuk digunakan dengan opsiconst
      '--foo', action='store_const', const=42 => args.foo == 42
    • count: untuk opsi berulang, seperti pada./myscript.py -vv
      '-v', action='count' => args.v == 2
    • append: untuk opsi berulang, seperti pada./myscript.py --foo 1 --foo 2
      '--foo', action='append' => args.foo == ['1', '2']
  • diperlukan : jika bendera diperlukan, atau argumen posisi tidak.
  • nargs : untuk sebuah flag untuk menangkap N args
    ./myscript.py --foo a b => args.foo = ['a', 'b']
  • pilihan : untuk membatasi input yang mungkin (tentukan sebagai daftar string, atau int jika type=int).
Jonathan H
sumber
12

Perhatikan Tutorial Argparse dalam Python HOWTOs . Dimulai dari sebagian besar contoh dasar, seperti ini:

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)

dan berkembang menjadi yang kurang mendasar.

Ada contoh dengan pilihan yang sudah ditentukan sebelumnya untuk suatu opsi, seperti apa yang ditanyakan:

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)
Alexey
sumber
Sangat menyenangkan melihat bahwa dokumen telah diperbarui. Saya yakinkan Anda ini tidak terjadi ketika OP memposting pertanyaan 5 tahun yang lalu.
ntwrkguru
10

Inilah yang saya hasilkan dalam proyek pembelajaran saya terutama berkat @DMH ...

Kode demo:

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

Ini mungkin telah berkembang dan tersedia online: command-line.py

Script untuk memberikan kode ini latihan: command-line-demo.sh

Peter L.
sumber
2
Akhirnya, contoh yang masuk akal yang masuk akal
opentokix
5

Anda juga bisa menggunakan plac (pembungkus argparse).

Sebagai bonus, ini menghasilkan instruksi bantuan yang rapi - lihat di bawah.

Skrip contoh:

#!/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)

Contoh output:

Tidak ada argumen yang diberikan - example.py :

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

Argumen yang tidak terduga disediakan - example.py C :

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

Argumen yang benar disertakan - example.py A :

Argument has value A

Menu bantuan penuh (dihasilkan secara otomatis) - 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

Penjelasan singkat:

Nama argumen biasanya sama dengan nama parameter ( arg).

Anotasi tuple setelah argparameter memiliki arti sebagai berikut:

  • Deskripsi ( Argument with two possible values)
  • Jenis argumen - salah satu dari 'bendera', 'opsi' atau 'posisi' ( positional)
  • Singkatan ( None)
  • Jenis nilai argumen - mis. float, string ( None)
  • Set pilihan terbatas ( ['A', 'B'])

Dokumentasi:

Untuk mempelajari lebih lanjut tentang cara menggunakan plac, lihat dokumentasinya yang luar biasa:

Letakkan: Memotong Baris Perintah dengan Cara Mudah

quasoft
sumber
4

Untuk menambah apa yang dikatakan orang lain:

Saya biasanya suka menggunakan parameter 'dest' untuk menentukan nama variabel dan kemudian menggunakan 'global () .perbarui ()' untuk meletakkan variabel-variabel tersebut di namespace global.

Pemakaian:

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

Kode:

...
parser.add_argument('-i', '--input', ..., dest='inputted_variable',...)
globals().update(vars(parser.parse_args()))
...
print(inputted_variable) # Prints "Hello, World!"
Sandy Chapman
sumber
argparseMenggunakan getattrdan setattrmengakses nilai di Namespace secara internal . Dengan begitu tidak terganggu oleh destnilai-nilai yang terbentuk secara aneh .
hpaulj
1

Cara yang sangat sederhana untuk menggunakan argparse dan mengubah switch '-h' / '--help' untuk menampilkan instruksi bantuan kode pribadi Anda adalah dengan mengatur bantuan default ke False, Anda juga dapat menambahkan sebanyak mungkin .add_arguments tambahan yang Anda inginkan :

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

Jalankan: python test.py -h

Keluaran:

usage: test.py [-h]

optional arguments:
  -h, --help  To run this script please provide two arguments
Kandang kelinci
sumber
-1

Jawaban paling sederhana!

PS orang yang menulis dokumen argparse itu bodoh

kode python:

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

menjalankan kode

python produce_result.py --o_dct_fname o_dct --tp father_child --new_res_set 1
gouxute
sumber
Jawaban ini tidak menambahkan sesuatu yang baru / berbeda dari jawaban yang ada.
NVS Abhilash
saya yang paling jelas, bicara itu murah, tunjukkan kodenya
gouxute