2025, Nov 01 13:02
कई फ़ाइलों के लिए अलग‑अलग फ्लैग्स: Python argparse की सीमाएँ और प्री‑प्रोसेसिंग समाधान
कई इनपुट फ़ाइलों पर प्रति‑फ़ाइल विकल्प चाहिए? जानें क्यों Python argparse सीधे सपोर्ट नहीं करता, intermixed parsing की हदें और sys.argv प्री‑प्रोसेसिंग से समाधान।
कई इनपुट फ़ाइलें लेने वाला और प्रत्येक फ़ाइल के लिए अलग‑अलग विकल्प स्वीकार करने वाला CLI बनाना पहली नज़र में आसान लगता है। आमतौर पर लगता है कि यह कॉल सीधे चलेगा: किसी फ़ाइल से पहले रखा फ्लैग केवल उसी फ़ाइल पर लागू हो, दूसरी फ़ाइल से पहले दूसरा फ्लैग — उस पर, और आगे भी ऐसा ही। ffmpeg जैसे टूल्स ने यही शैली लोकप्रिय की:
python my.py -a file_a -b file_b --do-stuff=x file_cargparse के साथ समस्या को दोहराकर देखना
यह न्यूनतम सेटअप दो‑तीन फ्लैग और इनपुट फ़ाइलों की पॉज़िशनल सूची परिभाषित करने की कोशिश करता है:
import argparse
import pathlib
cli = argparse.ArgumentParser()
cli.add_argument("-a", action="store_true")
cli.add_argument("-b", action="store_true")
cli.add_argument("--do-stuff", type=str)
cli.add_argument("files", type=pathlib.Path, nargs="+")
parsed = cli.parse_args()इसे ऊपर दिखाए गए तरीके से चलाएँ, और आपको यह मिलेगा:
error: unrecognized arguments: file_b file_cइस सिन्टैक्स के पीछे लक्ष्य यह है कि हर फ़ाइल के लिए कुछ इस तरह का मैपिंग निकले:
file_a: {a: True}
file_b: {b: True}
file_c: {do_stuff: 'x'}यह क्यों काम नहीं करता
-a और -b जैसे फ्लैग boolean होते हैं, वे कोई मान नहीं लेते। इसलिए file_a और file_b उन फ्लैग्स के मान के रूप में नहीं खपत होते; उन्हें पॉज़िशनल आर्ग्युमेंट माना जाता है। Python का ArgumentParser किसी विकल्प को निकटतम पॉज़िशनल आर्ग्युमेंट से नहीं जोड़ता, न ही परिणाम बनाते समय विकल्पों के क्रम को positionals के सापेक्ष देखता। डॉक्यूमेंटेशन में बताए गए intermixed parsing मोड (https://docs.python.org/3/library/argparse.html#intermixed-parsing) से भी यहाँ काम नहीं बनता। parse_intermixed_args या parse_known_intermixed_args को कॉल करने पर, parser सभी विकल्प निकाल लेता है — चाहे वे file_a या किसी अन्य पॉज़िशनल के सापेक्ष कहीं भी क्यों न आए हों। दूसरे शब्दों में, ऐसा कोई built-in तरीका नहीं है जिससे कहा जा सके: “यह फ्लैग सिर्फ अगली फ़ाइल के लिए है।”
प्री‑प्रोसेसिंग के साथ एक व्यावहारिक तरीका
चाहे गए व्यवहार की नकल करने के लिए आप sys.argv को प्री‑प्रोसेस कर सकते हैं: प्रत्येक फ़ाइल तक के आर्ग्युमेंट्स को स्लाइस करें और हर स्लाइस को अलग‑अलग पार्स करें। विचार यह है कि पहले फ़ाइलों की सूची निकाली जाए, फिर हर फ़ाइल के लिए केवल वे आर्ग्युमेंट पार्स किए जाएँ जो उससे पहले आते हैं। एक समायोजन ज़रूरी है: फ़ाइल नामों को str के रूप में पढ़ें ताकि बाद में उन्हें मूल argv क्रम में ढूँढा जा सके।
import sys
import argparse
import pathlib
cli = argparse.ArgumentParser()
cli.add_argument("-a", action="store_true")
cli.add_argument("-b", action="store_true")
cli.add_argument("--do-stuff", type=str)
# फ़ाइल नामों को str के रूप में पढ़ें ताकि बाद में उन्हें argv में ढूँढ सकें
cli.add_argument("files", type=str, nargs="+")
# विकल्पों की स्थिति को नज़रअंदाज़ करते हुए फ़ाइल नाम इकट्ठा करें
file_list = cli.parse_intermixed_args().files
per_input = {}
remaining = sys.argv[1:]
for fname in file_list:
# शेष argv स्लाइस में वर्तमान फ़ाइल खोजें
cut = remaining.index(fname) + 1
# केवल इस फ़ाइल से जुड़े आर्ग्युमेंट पार्स करें (इसके पहले तक और इसे शामिल करके)
per_input[pathlib.Path(fname)] = cli.parse_args(remaining[:cut])
# जो अभी पार्स किया है उसे हटा दें और आगे बढ़ें
del remaining[:cut]यह तरीका हर फ़ाइल से पहले आने वाले फ्लैग्स को अलग कर देता है और उन्हें ऐसे पार्स करता है मानो आपने हर इनपुट के लिए प्रोग्राम अलग‑अलग चलाया हो। Intermixed parsing वाला चरण केवल फ़ाइलों की सूची निकालने के लिए है, ताकि parser शुरुआत में ही सभी विकल्प न निगल ले।
यह क्यों मायने रखता है
यदि आप ffmpeg जैसी कमांड‑लाइन का अनुभव देना चाहते हैं, जहाँ विकल्पों का दायरा किसी विशिष्ट इनपुट तक सीमित किया जा सके, तो यह मान लेना कि ArgumentParser पॉज़िशनल संदर्भ का सम्मान करेगा — अप्रत्याशित नतीजों तक ले जाता है। यह समझना कि parser विकल्पों को पास के पॉज़िशनल्स से नहीं जोड़ता, आपको नाज़ुक इंटरफेस से बचाता है और यह स्पष्ट करता है कि कब प्री‑प्रोसेसिंग की ज़रूरत है।
मुख्य बातें
Python का ArgumentParser तर्कों के क्रम के आधार पर प्रति‑फ़ाइल विकल्प‑स्कोपिंग का समर्थन नहीं करता। Intermixed parsing विचार के स्तर पर पास तो आता है, लेकिन फिर भी फ़ाइलों के सापेक्ष उनकी स्थिति की परवाह किए बिना विकल्पों को समेट देता है। जब per‑input कॉन्फ़िगरेशन चाहिए, तो कच्चा argv खुद खंडों में बाँटें, हर खंड को पार्स करें और प्रति‑फ़ाइल मैपिंग को स्पष्ट रूप से तैयार करें। इससे कमांड की मूल शैली बनी रहती है और आपको वही साफ, फ़ाइल‑विशिष्ट विकल्प‑मैपिंग मिलती है जिसकी आप चाह रहे थे।