2014-12-11 15 views
11

के बजाय किसी विकल्प से फ़ाइल के तर्कों को पढ़ने के लिए argparse कैसे प्राप्त करें, मैं कमांड लाइन और संभावित रूप से टेक्स्ट फ़ाइलों से तर्क पढ़ने के लिए पाइथन के Argparse मॉड्यूल का उपयोग कैसे करना चाहता हूं। मैं argparse के fromfile_prefix_chars के बारे में जानता हूं लेकिन यह वही नहीं है जो मैं चाहता हूं। मुझे व्यवहार चाहिए, लेकिन मुझे सिंटैक्स नहीं चाहिए। मैं एक अंतरफलक है कि इस तरह दिखता है चाहता हूँ:उपसर्ग

$ python myprogram.py --foo 1 -A somefile.txt --bar 2 

जब argparse -एक देखता है, यह sys.argv या जो कुछ भी मैं इसे देने से पढ़ बंद कर देना चाहिए, और एक समारोह मैं लिखने कि somefile.text पढ़ा जाएगा और बदले फोन तर्कों की एक सूची। जब फ़ाइल समाप्त हो जाती है तो इसे पार्सिंग sys.argv या जो कुछ भी फिर से शुरू करना चाहिए। यह महत्वपूर्ण है कि फ़ाइल में तर्कों की प्रसंस्करण क्रम में हो (यानी: -फू को संसाधित किया जाना चाहिए, फिर फ़ाइल में तर्क, फिर -bar, ताकि फ़ाइल में तर्क ओवरराइड हो सकें - foo, और - बार फ़ाइल में क्या हो सकता है ओवरराइड हो सकता है)।

ऐसी चीज संभव है? क्या मैं एक कस्टम फ़ंक्शन लिख सकता हूं जो Argparse के स्टैक पर नए तर्क को दबाता है, या उस प्रभाव के लिए कुछ?

+0

आपके संस्करण में, एक तर्क के विशेष संचालन को ट्रिगर करेगा (उपसर्ग चरित्र के बजाय)? – martineau

+0

@ मार्टिनौ: "-ए" विकल्प कहता है "अगला तर्क एक फ़ाइल को पढ़ने के लिए है"। मुझे उस फ़ाइल को पढ़ने और तर्कों को वापस करने के लिए अपना स्वयं का फ़ंक्शन लिखने में सक्षम होना चाहिए (यह एक-तर्क-प्रति-पंक्ति प्रारूप में नहीं है) –

+0

[_parse_known_args] के स्रोत को देखकर (https: //hg.python। संगठन/cpython/फ़ाइल/3.4/लीब/argparse.py # l1769), ऐसा लगता है कि argparse सामने के सभी तर्कों को जानना पसंद करता है। अगर आपके पास @fromfile_prefix_chars सेट है, तो यह तर्कों को देखता है और पार्स (_read_args_from_files) के लिए पूरी तरह से नई सूची बनाता है। मुझे लगता है कि तर्कों की सूची प्राप्त करने के लिए समय से पहले sys.argv को पार्स करना आपका सबसे अच्छा विकल्प है। – mgilson

उत्तर

19

आप एक कस्टम argparse.Action फ़ाइल को खोलता है कि का उपयोग करके इस हल कर सकते हैं, फ़ाइल की सामग्री को पार्स करता है और उसके बाद तो तर्क कहते हैं।

उदाहरण के लिए यह एक बहुत ही सरल कार्रवाई होगी:

class LoadFromFile (argparse.Action): 
    def __call__ (self, parser, namespace, values, option_string = None): 
     with values as f: 
      parser.parse_args(f.read().split(), namespace) 

कौन सा आप कर सकते हैं इस तरह उपयोग करें:

parser = argparse.ArgumentParser() 
# other arguments 
parser.add_argument('--file', type=open, action=LoadFromFile) 
args = parser.parse_args() 

args में जिसके परिणामस्वरूप नाम स्थान तो भी किसी भी विन्यास है कि यह भी था शामिल होंगे फ़ाइल से भरा हुआ है।

यदि आपको अधिक परिष्कृत पार्सिंग की आवश्यकता है, तो आप इन-फाइल कॉन्फ़िगरेशन को अलग से पहले भी पार्स कर सकते हैं और फिर चयन करें कि कौन से मूल्यों को लिया जाना चाहिए। उदाहरण के लिए, यह हो सकता है समझ में कॉन्फ़िग फ़ाइल में को निर्दिष्ट एक और फ़ाइल अस्वीकृत करने के लिए:

def __call__ (self, parser, namespace, values, option_string=None): 
    with values as f: 
     contents = f.read() 

    data = parser.parse_args(contents.split(), namespace=namespace) 
    for k, v in vars(data).items(): 
     if v and k != option_string.lstrip('-'): 
      setattr(namespace, k, v) 
बेशक

, आप भी, फ़ाइल में थोड़ा और अधिक जटिल बना सकता है पढ़ने उदाहरण पहले JSON से पढ़ने के लिए।

+0

Ah-ha! कुंजी यह महसूस कर रही है कि पार्सर कस्टम कार्रवाई में पारित किया गया है, और आप फ़ाइल की सामग्री को संसाधित करने के लिए उस पार्सर का उपयोग कर सकते हैं। धन्यवाद। –

+0

लेकिन यदि वैश्विक पर्यावरण में पार्सर का अलग नाम था, तो यह अभी भी यहां उपलब्ध होगा। तो यहां कोई पार्सर इस्तेमाल किया जा सकता है। पैरामीटर के रूप में पारित 'पार्सर' के बारे में कुछ खास नहीं है। – hpaulj

+1

हां, यह विफल रहता है यदि आपके किसी भी पैरामीटर को आवश्यक पर सेट किया गया है। –

1

एक Action, जिसे कॉल किया जाता है, parser और namespace अपने तर्कों के बीच मिलता है।

तो आप बाद अद्यतन करने के लिए पूर्व के माध्यम से अपनी फ़ाइल रख सकते हैं:

class ArgfileAction(argparse.Action): 
    def __call__(self, parser, namespace, values, option_string=None): 
     extra_args = <parse_the_file>(values) 
     #`namespace' is updated in-place when specified 
     parser.parse_args(extra_args,namespace) 
+3

मेरा मानना ​​है कि ओपी पहले से ही इस विशेषता के बारे में जानता है जैसा कि "मैं Argparse के fromfile_prefix_chars के बारे में जानता हूं लेकिन यह वही नहीं है जो मैं चाहता हूं" – mgilson

2

आप टिप्पणी की है कि

मैं अपने खुद के समारोह लिखने के लिए फाइल को पढ़ने और तर्क वापसी (यह एक एक तर्क-प्रति-लाइन प्रारूप में नहीं है) करने में सक्षम होने की जरूरत है -

फ़ाइल को पढ़ने के तरीके को बदलने के लिए मौजूदा उपसर्ग-फ़ाइल हैंडलर में एक प्रावधान है। फ़ाइल एक 'निजी' विधि, parser._read_args_from_files द्वारा पढ़ा जाता है, लेकिन यह एक सरल सार्वजनिक विधि है कि तार के लिए एक लाइन धर्मान्तरित कहता है, डिफ़ॉल्ट एक तर्क-प्रति-लाइन कार्रवाई:

def convert_arg_line_to_args(self, arg_line): 
    return [arg_line] 

यह इस तरह से इतना लिखा गया था आप आसानी से इसे अनुकूलित कर सकते हैं।

test_argparse.py unittesting फ़ाइल में इस विकल्प के लिए एक परीक्षण का मामला है: https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.convert_arg_line_to_args

इस पद्धति की एक उपयोगी ओवरराइड एक है कि एक तर्क के रूप प्रत्येक स्थान से अलग किए शब्द व्यवहार करता है।


लेकिन अगर आप अभी एक उपसर्ग चरित्र के बजाय, एक तर्क विकल्प के साथ यह पढ़ने को गति प्रदान करना चाहते हैं, तो कस्टम कार्रवाई दृष्टिकोण एक अच्छा एक है।

हालांकि आप अपना खुद का फ़ंक्शन लिख सकते हैं जो को parser पर पास करने से पहले संसाधित करता है। इसे parser._read_args_from_files पर मॉडलिंग किया जा सकता है।

तो आप की तरह एक समारोह लिख सकते हैं:

parser.parse_args(read_my_file(sys.argv[1:])) 

और हाँ, यह एक ArgumentParser उपवर्ग में लिपटे जा सकता है:

def read_my_file(argv): 
    # if there is a '-A' string in argv, replace it, and the following filename 
    # with the contents of the file (as strings) 
    # you can adapt code from _read_args_from_files 
    new_argv = [] 
    for a in argv: 
     .... 
     # details left to user 
    return new_argv 

फिर साथ अपने पार्सर आह्वान।

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