अजगर का तर्क: कम से कम एक तर्क की आवश्यकता है


92

मैं argparseएक पायथन प्रोग्राम के लिए उपयोग कर रहा हूँ जो कर सकते हैं -process, -uploadया दोनों:

parser = argparse.ArgumentParser(description='Log archiver arguments.')
parser.add_argument('-process', action='store_true')
parser.add_argument('-upload',  action='store_true')
args = parser.parse_args()

कम से कम एक पैरामीटर के बिना कार्यक्रम अर्थहीन है। मैं argparseकम से कम एक पैरामीटर को चुनने के लिए मजबूर करने के लिए कैसे कॉन्फ़िगर कर सकता हूं ?

अपडेट करें:

टिप्पणियों के बाद: कम से कम एक विकल्प के साथ एक कार्यक्रम को पंगु बनाने का पाइथोनिक तरीका क्या है?


9
-xसार्वभौमिक रूप से एक ध्वज और वैकल्पिक है। -यदि आवश्यक हो तो काटें ।

1
क्या आप processडिफ़ॉल्ट व्यवहार नहीं कर सकते (कोई विकल्प निर्दिष्ट करने की आवश्यकता के बिना) और उपयोगकर्ता को यह बदलने की अनुमति देता है कि uploadक्या वह विकल्प सेट है? आमतौर पर, विकल्प वैकल्पिक होना चाहिए, इसलिए नाम। आवश्यक विकल्पों से बचा जाना चाहिए (यह argparse डॉक्स में भी है )।
टिम पीत्ज़ेकर

@AdamMatan आपको अपना सवाल पूछे लगभग तीन साल हो गए हैं लेकिन मुझे इसमें छिपी चुनौती पसंद आई और इस तरह के कार्यों के लिए उपलब्ध नए समाधानों का फायदा उठाया।
Jan Vlcinsky

जवाबों:


107
if not (args.process or args.upload):
    parser.error('No action requested, add -process or -upload')

1
यह शायद एकमात्र तरीका है, अगर argparseइसके लिए कोई अंतर्निहित विकल्प नहीं है।
एडम मटन

29
args = vars(parser.parse_args())
if not any(args.values()):
    parser.error('No arguments provided.')

3
एक सामान्यीकृत समाधान के लिए +1। इसके उपयोग की तरह vars(), जो ** के साथ एक कंस्ट्रक्टर के लिए सावधानीपूर्वक नामित विकल्पों को पारित करने के लिए भी उपयोगी है।
लेनना

जो वास्तव में मैं इसके साथ कर रहा हूं। धन्यवाद!
ब्रेंटलेंस

1
डांग, मुझे वह पसंद है vars। मैंने बस किया .__dict__और पहले गूंगा महसूस किया।
थियो बेलियार

1
शानदार जवाब। "Var" और "any" दोनों मेरे लिए नए थे :-)
विवेक झा

21

यदि 'या दोनों' भाग नहीं है (मैंने शुरू में इसे याद किया है) तो आप इस तरह से कुछ का उपयोग कर सकते हैं:

parser = argparse.ArgumentParser(description='Log archiver arguments.')
parser.add_argument('--process', action='store_const', const='process', dest='mode')
parser.add_argument('--upload',  action='store_const', const='upload', dest='mode')
args = parser.parse_args()
if not args.mode:
    parser.error("One of --process or --upload must be given")

हालांकि, शायद इसके बजाय उप-क्षेत्र का उपयोग करना बेहतर होगा ।


4
मुझे लगता है कि वह --processया तो अनुमति देना चाहता है --upload, एक्सओआर नहीं। यह दोनों विकल्पों को एक ही समय पर सेट होने से रोकता है।
फ़िहग

+1 क्योंकि आपने उप-भूमि का उल्लेख किया है। फिर भी - जैसा कि किसी ने टिप्पणियों में बताया है -xऔर --xxxआमतौर पर वैकल्पिक पैरामीटर हैं।
मैक

20

मुझे पता है कि यह गंदगी के रूप में पुराना है, लेकिन एक विकल्प की आवश्यकता है लेकिन एक से अधिक (XOR) की मनाही इस तरह है:

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-process', action='store_true')
group.add_argument('-upload',  action='store_true')
args = parser.parse_args()
print args

आउटपुट:

>opt.py  
usage: multiplot.py [-h] (-process | -upload)  
multiplot.py: error: one of the arguments -process -upload is required  

>opt.py -upload  
Namespace(process=False, upload=True)  

>opt.py -process  
Namespace(process=True, upload=False)  

>opt.py -upload -process  
usage: multiplot.py [-h] (-process | -upload)  
multiplot.py: error: argument -process: not allowed with argument -upload  

3
दुर्भाग्य से, ओपी एक XOR नहीं चाहता है। यह या तो दोनों है, लेकिन ऐसा नहीं है कि आपका अंतिम परीक्षण मामला उनकी आवश्यकताओं को पूरा नहीं करता है।
kdopen

2
@kdopen: प्रतिवादी ने स्पष्ट किया कि यह मूल प्रश्न पर एक भिन्नता है, जो मुझे उपयोगी लगी: "एक विकल्प की आवश्यकता है लेकिन एक से अधिक के लिए मना करने का तरीका" शायद स्टैक एक्सचेंज का शिष्टाचार इसके बजाय एक नए प्रश्न के लिए कॉल करेगा। । लेकिन यहाँ मौजूद इस जवाब से मुझे मदद मिली ...
erik.weathers

2
यह पोस्ट प्रारंभिक प्रश्न का उत्तर नहीं देती है
मार्क

2
यह "कम से कम एक" के सवाल का जवाब कैसे देता है?
xaxxon

2
दुर्भाग्य से, ओपी एक XOR नहीं चाहता है।
duckman_1991

8

आवश्यकताएँ समीक्षा

  • उपयोग argparse(मैं इसे अनदेखा करूँगा)
  • एक या दो क्रियाओं को करने की अनुमति दें (कम से कम एक आवश्यक)।
  • पाइथोनिक द्वारा प्रयास करें (मैं इसे "POSIX"-समान कहना चाहूंगा)

कमांड लाइन पर रहने पर कुछ निहित आवश्यकताएं भी हैं:

  • उपयोगकर्ता के उपयोग को इस तरह से समझाएं जो समझने में आसान हो
  • विकल्प वैकल्पिक होंगे
  • झंडे और विकल्पों को निर्दिष्ट करने की अनुमति दें
  • अन्य मापदंडों (जैसे फ़ाइल नाम या नाम) के साथ संयोजन की अनुमति दें।

नमूना समाधान का उपयोग कर docopt(फ़ाइल managelog.py):

"""Manage logfiles
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  Password

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>
"""
if __name__ == "__main__":
    from docopt import docopt
    args = docopt(__doc__)
    print args

इसे चलाने का प्रयास करें:

$ python managelog.py
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

मदद दिखाएँ:

$ python managelog.py -h
Manage logfiles
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  P    managelog.py [options] upload -- <logfile>...

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>

और इसका उपयोग करें:

$ python managelog.py -V -U user -P secret upload -- alfa.log beta.log
{'--': True,
 '--pswd': 'secret',
 '--user': 'user',
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': False,
 'upload': True}

संक्षिप्त विकल्प short.py

और भी छोटे संस्करण हो सकते हैं:

"""Manage logfiles
Usage:
    short.py [options] (process|upload)... -- <logfile>...
    short.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  Password

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>
"""
if __name__ == "__main__":
    from docopt import docopt
    args = docopt(__doc__)
    print args

उपयोग इस तरह दिखता है:

$ python short.py -V process upload  -- alfa.log beta.log
{'--': True,
 '--pswd': None,
 '--user': None,
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': 1,
 'upload': 1}

ध्यान दें, कि "प्रक्रिया" और "अपलोड" कुंजी के लिए बूलियन मानों के बजाय काउंटर हैं।

यह पता चला है, हम इन शब्दों के दोहराव को नहीं रोक सकते:

$ python short.py -V process process upload  -- alfa.log beta.log
{'--': True,
 '--pswd': None,
 '--user': None,
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': 2,
 'upload': 1}

निष्कर्ष

अच्छा कमांड लाइन इंटरफ़ेस डिजाइन करना कुछ समय के लिए चुनौतीपूर्ण हो सकता है।

कमांड लाइन आधारित कार्यक्रम के कई पहलू हैं:

  • कमांड लाइन का अच्छा डिजाइन
  • उचित पार्सर का चयन / उपयोग करना

argparse बहुत कुछ प्रदान करता है, लेकिन संभव परिदृश्यों को प्रतिबंधित करता है और बहुत जटिल बन सकता है।

साथ docoptबातें बहुत कम है, जबकि पठनीयता संरक्षण और लचीलेपन के उच्च स्तर की पेशकश जाना। यदि आप शब्दकोश से पार्स किए गए तर्क प्राप्त कर रहे हैं और कुछ रूपांतरण (पूर्णांक, खोलने वाली फाइलें ..) मैन्युअल रूप से (या अन्य पुस्तकालय नाम से schema) करते हैं, तो आप docoptकमांड लाइन पार्सिंग के लिए उपयुक्त हो सकते हैं ।


डॉकॉप्ट के बारे में कभी नहीं सुना, बढ़िया सुझाव!
टन वैन डेन हेउवेल

@TonvandenHeuvel अच्छा है। मैं सिर्फ पुष्टि करना चाहता हूं, मैं अभी भी कमांड लाइन इंटरफेस के लिए मेरे पसंदीदा समाधान के रूप में उपयोग कर रहा हूं।
Jan Vlcinsky

सबसे अच्छा उत्तर स्पष्ट, विस्तृत उदाहरण के लिए धन्यवाद।
jnovack

5

यदि आपको कम से कम एक पैरामीटर के साथ चलने के लिए एक अजगर कार्यक्रम की आवश्यकता होती है, तो एक तर्क जोड़ें जिसमें विकल्प उपसर्ग नहीं है (- या - डिफ़ॉल्ट रूप से) और सेट nargs=+(न्यूनतम एक तर्क की आवश्यकता)। इस पद्धति की समस्या मुझे यह लगी कि यदि आप तर्क निर्दिष्ट नहीं करते हैं, तो argparse "बहुत कम तर्क" त्रुटि उत्पन्न करेगा और मदद मेनू का प्रिंट आउट नहीं लेगा। यदि आपको उस कार्यक्षमता की आवश्यकता नहीं है, तो इसे कोड में कैसे करें:

import argparse

parser = argparse.ArgumentParser(description='Your program description')
parser.add_argument('command', nargs="+", help='describe what a command is')
args = parser.parse_args()

मुझे लगता है कि जब आप विकल्प उपसर्गों के साथ एक तर्क जोड़ते हैं, तो नर्ग पूरे तर्क पार्सर को नियंत्रित करता है, न कि केवल विकल्प को। (मेरा क्या मतलब है, यदि आपके पास एक --optionझंडा है nargs="+", तो --optionझंडा कम से कम एक तर्क की अपेक्षा करता है। यदि आपके पास optionहै nargs="+", तो यह कम से कम एक तर्क की अपेक्षा करता है।)


आप choices=['process','upload']उस तर्क में जोड़ सकते हैं ।
हंपूल

5

के लिए http://bugs.python.org/issue11588 मैं सामान्यीकरण के तरीकों की तलाश कर रहा हूँmutually_exclusive_group इस तरह के मामलों को संभालने के लिए अवधारणा।

इस विकास के साथ argparse.py, https://github.com/hpaulj/argparse_issues/blob/nested/argparse.py मैं लिखने में सक्षम हूं:

parser = argparse.ArgumentParser(prog='PROG', 
    description='Log archiver arguments.')
group = parser.add_usage_group(kind='any', required=True,
    title='possible actions (at least one is required)')
group.add_argument('-p', '--process', action='store_true')
group.add_argument('-u', '--upload',  action='store_true')
args = parser.parse_args()
print(args)

जो निम्नलिखित उत्पादन करता है help:

usage: PROG [-h] (-p | -u)

Log archiver arguments.

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

possible actions (at least one is required):
  -p, --process
  -u, --upload

यह '-u', '-up', '--proc --up' आदि जैसे इनपुट्स को स्वीकार करता है।

यह https://stackoverflow.com/a/6723066/901925 के समान एक परीक्षण चलाने के लिए समाप्त होता है , हालांकि त्रुटि संदेश को स्पष्ट करने की आवश्यकता होती है:

usage: PROG [-h] (-p | -u)
PROG: error: some of the arguments process upload is required

मैं सोचता हूं:

  • क्या पैरामीटर kind='any', required=Trueपर्याप्त रूप से स्पष्ट हैं (किसी भी समूह को स्वीकार करते हैं? कम से कम एक की आवश्यकता है)?

  • क्या उपयोग (-p | -u)स्पष्ट है? एक आवश्यक रूप से पारस्परिक रूप से एक ही चीज़ उत्पन्न करता है। क्या कोई वैकल्पिक संकेतन है?

  • phihag'sसरल परीक्षण की तुलना में इस तरह के एक समूह का उपयोग करना अधिक सहज है ?


मुझे add_usage_groupइस पृष्ठ पर कोई उल्लेख नहीं मिल रहा है : docs.python.org/2/library/argparse.html ; क्या आप इसके लिए दस्तावेज़ का लिंक प्रदान करेंगे?
पी। मायर नोरे

@ P.MyerNore, मैंने इस उत्तर की शुरुआत में एक लिंक प्रदान किया था। इसे उत्पादन में नहीं डाला गया है।
हापुलज

5

सबसे अच्छा तरीका यह है कि अजगर इनबिल्ट मॉड्यूल add_mutually_exclusive_group का उपयोग करके है ।

parser = argparse.ArgumentParser(description='Log archiver arguments.')
group = parser.add_mutually_exclusive_group()
group.add_argument('-process', action='store_true')
group.add_argument('-upload',  action='store_true')
args = parser.parse_args()

यदि आप चाहते हैं कि कमांड लाइन द्वारा केवल एक तर्क का चयन किया जाए तो समूह के लिए तर्क के रूप में आवश्यक = सही का उपयोग करें

group = parser.add_mutually_exclusive_group(required=True)

2
यह आपको "कम से कम एक" कैसे मिलता है - क्या यह आपको "बिल्कुल एक" नहीं मिलता है?
xaxxon

3
दुर्भाग्य से, ओपी एक XOR नहीं चाहता है। ओपी की तलाश है
duckman_1991

इसने ओपी के सवाल का जवाब नहीं दिया, लेकिन इसने मेरा जवाब दिया, वैसे भी धन्यवाद (_ (_) _ / ¯
rosstex

2

शायद उप-पार्सर का उपयोग करें?

import argparse

parser = argparse.ArgumentParser(description='Log archiver arguments.')
subparsers = parser.add_subparsers(dest='subparser_name', help='sub-command help')
parser_process = subparsers.add_parser('process', help='Process logs')
parser_upload = subparsers.add_parser('upload', help='Upload logs')
args = parser.parse_args()

print("Subparser: ", args.subparser_name)

अब --helpदिखाता है:

$ python /tmp/aaa.py --help
usage: aaa.py [-h] {process,upload} ...

Log archiver arguments.

positional arguments:
  {process,upload}  sub-command help
    process         Process logs
    upload          Upload logs

optional arguments:
  -h, --help        show this help message and exit
$ python /tmp/aaa.py
usage: aaa.py [-h] {process,upload} ...
aaa.py: error: too few arguments
$ python3 /tmp/aaa.py upload
Subparser:  upload

आप इन उप-पार्सरों में अतिरिक्त विकल्प भी जोड़ सकते हैं। इसके अलावा इसका उपयोग करने के बजाय dest='subparser_name'आप दिए गए उप-आदेश पर सीधे कॉल किए जाने वाले फ़ंक्शन को भी बाइंड कर सकते हैं (डॉक्स देखें)।


2

यह उद्देश्य को प्राप्त करता है और यह भी argparse autogenerated --helpउत्पादन में relfected होगा , जो कि सबसे अधिक समझदार प्रोग्रामर क्या चाहते हैं (यह भी वैकल्पिक तर्कों के साथ काम करता है):

parser.add_argument(
    'commands',
    nargs='+',                      # require at least 1
    choices=['process', 'upload'],  # restrict the choice
    help='commands to execute'
)

इस पर आधिकारिक डॉक्स: https://docs.python.org/3/library/argparse.html#choices


1

कार्यों की सूची में append_const का प्रयोग करें और फिर जाँचें कि सूची आबाद है:

parser.add_argument('-process', dest=actions, const="process", action='append_const')
parser.add_argument('-upload',  dest=actions, const="upload", action='append_const')

args = parser.parse_args()

if(args.actions == None):
    parser.error('Error: No actions requested')

तुम भी लगातार स्थिरांक के भीतर तरीकों को निर्दिष्ट कर सकते हैं।

def upload:
    ...

parser.add_argument('-upload',  dest=actions, const=upload, action='append_const')
args = parser.parse_args()

if(args.actions == None):
    parser.error('Error: No actions requested')

else:
    for action in args.actions:
        action()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.