2011-03-21 14 views
16

के साथ एकाधिक स्थितित्मक तर्क मैं एक प्रोग्राम के लिए कमांड लाइन तर्कों को पार्स करने के लिए argparse का उपयोग करने का प्रयास कर रहा हूं। अनिवार्य रूप से, मुझे वैकल्पिक तर्कों के भीतर फैले कई पोजीशनल तर्कों का समर्थन करने की आवश्यकता है, लेकिन इस स्थिति में काम करने के लिए तर्क नहीं मिल सकता है। वास्तविक कार्यक्रम में, मैं एक कस्टम एक्शन का उपयोग कर रहा हूं (मुझे प्रत्येक बार एक स्थितित्मक तर्क मिलने पर नामस्थान का स्नैपशॉट स्टोर करने की आवश्यकता होती है), लेकिन मुझे जो समस्या हो रही है उसे append क्रिया के साथ दोहराया जा सकता है:पायथन और Argparse

>>> import argparse 
>>> parser = argparse.ArgumentParser() 
>>> parser.add_argument('-a', action='store_true') 
>>> parser.add_argument('-b', action='store_true') 
>>> parser.add_argument('input', action='append') 
>>> parser.parse_args(['fileone', '-a', 'filetwo', '-b', 'filethree']) 
usage: ipython [-h] [-a] [-b] input 
ipython: error: unrecognized arguments: filetwo filethree 

मैं इसे नामस्थान (a=True, b=True, input=['fileone', 'filetwo', 'filethree']) में परिणाम देना चाहता हूं, लेकिन यह नहीं देख सकता कि यह कैसे करें - यदि वास्तव में यह कर सकता है। मैं दस्तावेज़ों या Google में कुछ भी नहीं देख सकता जो एक तरीका या दूसरा कहता है यदि यह संभव है, हालांकि यह काफी संभव है (संभवतः?) मैंने कुछ अनदेखा किया है। क्या किसी के पास कोई सुझाव है?

+0

'' -a'' और '' -b'' की क्रिया को 'ऐपेंड'' में बदलने के बारे में, फिर परिणामस्वरूप नामस्थान को आप जो चाहते हैं उसे संशोधित करें? –

उत्तर

7

srgerg स्थितीय तर्कों की परिभाषा के बारे में सही था। परिणाम प्राप्त करने के लिए, आपको उन्हें वैकल्पिक तर्क के रूप में स्वीकार करना होगा, और आपकी आवश्यकता के अनुसार परिणामस्वरूप नामस्थान को संशोधित करना होगा।

आप एक कस्टम क्रिया का उपयोग कर सकते हैं:

class MyAction(argparse.Action): 
    def __call__(self, parser, namespace, values, option_string=None): 

     # Set optional arguments to True or False 
     if option_string: 
      attr = True if values else False 
      setattr(namespace, self.dest, attr) 

     # Modify value of "input" in the namespace 
     if hasattr(namespace, 'input'): 
      current_values = getattr(namespace, 'input') 
      try: 
       current_values.extend(values) 
      except AttributeError: 
       current_values = values 
      finally: 
       setattr(namespace, 'input', current_values) 
     else: 
      setattr(namespace, 'input', values) 

parser = argparse.ArgumentParser() 
parser.add_argument('-a', nargs='+', action=MyAction) 
parser.add_argument('-b', nargs='+', action=MyAction) 
parser.add_argument('input', nargs='+', action=MyAction) 

और यह आप क्या मिलता है:

>>> parser.parse_args(['fileone', '-a', 'filetwo', '-b', 'filethree']) 
Namespace(a=True, b=True, input=['fileone', 'filetwo', 'filethree']) 

या आप इस तरह के परिणामस्वरूप नाम स्थान को संशोधित कर सकते हैं:

>>> import argparse 
>>> parser = argparse.ArgumentParser() 
>>> parser.add_argument('-a', nargs='+') 
>>> parser.add_argument('-b', nargs='+') 
>>> parser.add_argument('input', nargs='+') 
>>> result = parser.parse_args(['fileone', '-a', 'filetwo', '-b', 'filethree']) 

>>> inputs = [] 
>>> inputs.extend(result.a) 
>>> inputs.extend(result.b) 
>>> inputs.extend(result.input) 

>>> modified = argparse.Namespace(
     a = result.a != [], 
     b = result.b != [], 
     input = inputs) 

और यह आपको मिलता है:

>>> modified 
Namespace(a=True, b=True, input=['filetwo', 'filethree', 'fileone']) 

हालांकि, दोनों विधिओं के परिणामस्वरूप कम पठनीय और कम रखरखाव कोड होता है। शायद प्रोग्राम तर्क को बदलना और इसे अलग तरीके से करना बेहतर है।

+0

धन्यवाद उदाहरण के लिए। मैं एकाधिक पोजिशनल तर्कों का समर्थन करने में सक्षम होना चाहता हूं, लेकिन साथ ही मैं इस तरह के कामकाज को बनाए रखना नहीं चाहता हूं। ऐसा लगता है कि मेरे पास कुछ निर्णय लेने हैं ... – Blair

16

आप इस तरह से स्थितित्मक तर्क (यानी फाइलोन, फाइलटवो और फाइलथ्री) के साथ स्विच (यानी -a और -b) को इंटरलीव नहीं कर सकते हैं। स्विच को स्थितित्मक तर्कों के पहले या बाद में दिखाई देना चाहिए, बीच में नहीं।

इसके अलावा, एकाधिक स्थितित्मक तर्क रखने के लिए, आपको पैरामीटर add_argument पर निर्दिष्ट करने की आवश्यकता है। उदाहरण के लिए:

parser.add_argument('input', nargs='+') 

यह argparse बताता है एक या अधिक स्थितीय तर्क उपभोग करते हैं और उन्हें एक सूची में जोड़ने के लिए। अधिक जानकारी के लिए argparse documentation देखें।

parser.parse_args(['-a', '-b', 'fileone', 'filetwo', 'filethree']) 

परिणामों में: इस लाइन, कोड के साथ

Namespace(a=True, b=True, input=['fileone', 'filetwo', 'filethree']) 
+0

ओपी चाहता था बिल्कुल नहीं। 'parser.parse_args (['fileone', '-a', 'filetwo', '-b', 'filethree']' 'एक ही त्रुटि संदेश देता है। –

+2

सच है, लेकिन जैसा कि मैंने अपने उत्तर की शुरुआत में समझाया , आप स्थितित्मक तर्कों (उदाहरण के लिए fileone, filetwo, ...) के साथ स्विच (जैसे '-a') को अंतःस्थापित नहीं कर सकते हैं। आप _must_ को स्थितित्मक तर्कों से पहले या बाद में स्विच डालते हैं। – srgerg

+0

उत्तर के लिए धन्यवाद, मैं असमर्थ था दस्तावेज में एक निश्चित हां या नहीं ढूंढने के लिए यह समर्थित था कि – Blair

2

'संलग्न' कार्रवाई एक वैकल्पिक के साथ और अधिक समझ में आता है:

parser.add_argument('-i', '--input',action='append') 
parser.parse_args(['-i','fileone', '-a', '-i','filetwo', '-b', '-i','filethree']) 

आप अलग positionals ('इनपुट 1-एक इनपुट 2 बी इनपुट 3') के साथ optionals बिछा कर सकते हैं, लेकिन आप एक multiitem भीतर optionals बिछा नहीं कर सकते स्थितीय। लेकिन आप इसे दो चरण पार्स के साथ पूरा कर सकते हैं।

import argparse 
parser1 = argparse.ArgumentParser() 
parser1.add_argument('-a', action='store_true') 
parser1.add_argument('-b', action='store_true') 
parser2 = argparse.ArgumentParser() 
parser2.add_argument('input', nargs='*') 

ns, rest = parser1.parse_known_args(['fileone', '-a', 'filetwo', '-b', 'filethree']) 
# Namespace(a=True, b=True), ['fileone', 'filetwo', 'filethree'] 

ns = parser2.parse_args(rest, ns) 
# Namespace(a=True, b=True, input=['fileone', 'filetwo', 'filethree']) 

http://bugs.python.org/issue14191 एक प्रस्तावित पैच कि करने के लिए एक फोन के साथ ऐसा नहीं है:

parser.parse_intermixed_args(['fileone', '-a', 'filetwo', '-b', 'filethree']) 
1

यह मेरे लिए सही रास्ते पर है कि hpaulj लगता है, लेकिन चीज़ें थोड़ी आवश्यकता से अधिक जटिल बना रही है। मुझे संदेह है कि ब्लेयर पुराने ऑप्टपरसे मॉड्यूल के व्यवहार के समान कुछ ढूंढ रहा है और वास्तव में तर्क ऑब्जेक्ट के इनपुट फ़ील्ड में इनपुट तर्कों की सूची की आवश्यकता नहीं है। वह सिर्फ चाहता

import argparse 
parser = argparse.ArgumentParser() 
parser.add_argument('-a', action='store_true') 
parser.add_argument('-b', action='store_true') 
opts, args = parser.parse_known_args(['fileone', '-a', 'filetwo', '-b', 'filethree']) 
# Namespace(a=True, b=True), ['fileone', 'filetwo', 'filethree'] 

optparse की स्थानीय भाषा में, "विकल्प" opts में उपलब्ध हैं, और संभवतः की सूची अन्य "तर्कों" बीच-बीच में आर्ग में हैं।

संबंधित मुद्दे