2025, Oct 22 19:31
argparse में mutually exclusive फ्लैग्स और nargs='?' का बग: कारण व समाधान
Python 3.13.0 में argparse के mutually exclusive फ्लैग्स (nargs='?') बिना मान पर टकराव से बचते थे; 3.13.1+ में फिक्स। कारण, प्रभाव और अपग्रेड/डिज़ाइन टिप्स जानें।
argparse में mutually exclusive फ्लैग्स का मकसद यूज़र को परस्पर-विरोधी विकल्पों को एक साथ चुनने से रोकना है। लेकिन जब ये फ्लैग्स nargs='?' (वैकल्पिक मान) का इस्तेमाल करते हैं, तब मामला पेचीदा हो सकता है। Python 3.13.0 में, अगर ऐसे दो फ्लैग्स बिना किसी मान के दिए जाते थे, तो वे एक्सक्लूसिविटी जांच से बच सकते थे। यह इसलिए चौंकाता था क्योंकि इन्हीं फ्लैग्स को मान के साथ देने पर सही तरह से त्रुटि आती थी।
न्यूनतम सेटअप: वैकल्पिक मान वाला वैकल्पिक फ्लैग
इस व्यवहार को समझने के लिए, पहले nargs='?' वाले एक अकेले फ्लैग से शुरुआत करें। यह फ्लैग वैकल्पिक मान स्वीकार करता है, इसलिए केवल फ्लैग देना भी मान्य है और एक विशेष मान लौटाता है।
from argparse import ArgumentParser
cli = ArgumentParser()
cli.add_argument("--flag", nargs="?")
opts = cli.parse_args()
इस संरचना में, --flag 123 देने पर 123 सहेजा जाता है, खाली --flag देने पर None सहेजता है, और --flag को छोड़ देने पर भी None ही सहेजता है।
एक्सक्लूसिविटी वाला आश्चर्य कैसे दोहराएँ
अब ऐसे दो फ्लैग्स को एक mutually exclusive समूह में रखें। दोनों को मान के साथ देना त्रुटि उठाना चाहिए, और ऐसा होता भी है। मोड़ तब आता है जब दोनों फ्लैग्स बिना मान के दिए जाते हैं।
from argparse import ArgumentParser
cli = ArgumentParser()
exclusive = cli.add_mutually_exclusive_group()
exclusive.add_argument("--alpha", nargs="?")
exclusive.add_argument("--beta", nargs="?")
parsed = cli.parse_args()
उम्मीद के मुताबिक, --alpha 123 --beta 456 “not allowed” के साथ असफल होता है क्योंकि दोनों मौजूद हैं। लेकिन Python 3.13.0 पर, --alpha --beta चलाना बिना किसी त्रुटि के पूरा हो सकता था।
असल में हो क्या रहा है
nargs='?' तीन अवस्थाएँ बनाता है: फ्लैग नहीं दिया गया, खाली फ्लैग, और मान के साथ फ्लैग। जब डिफ़ॉल्ट None होता है, तो “नहीं दिया गया” और “खाली” दोनों ही None पर आकर मिल जाते हैं, जिससे यह पहचानना मुश्किल हो जाता है कि यूज़र ने खाली फ्लैग दिया था या बिल्कुल नहीं दिया। Python 3.13.0 में यह mutual exclusivity के साथ ठीक से नहीं मिला: जिन आर्ग्युमेंट्स का मान डिफ़ॉल्ट से मेल खाता था, उन्हें ऐसा माना जा सकता था मानो वे दिए ही नहीं गए।
Arguments with the value identical to the default value (e.g. booleans, small integers, empty or 1-character strings) are no longer considered "not present".
इस पुराने मुद्दे को Python 3.13.1 में संबोधित किया गया। रिपोर्ट्स बताती हैं कि मौजूदा 3.13.x रिलीज़ (उदाहरण के लिए, 3.13.5) पर --alpha --beta देने पर अपेक्षित त्रुटि उठती है।
समाधान
इसके लिए कोड बदलने की ज़रूरत नहीं है। बस Python को 3.13.1 या नए संस्करण पर अपग्रेड करें। इसके बाद, वही प्रोग्राम मान के साथ दिए गए और खाली—दोनों तरह के फ्लैग्स पर mutual exclusivity को सही ढंग से लागू करेगा।
from argparse import ArgumentParser
cli = ArgumentParser()
exclusive = cli.add_mutually_exclusive_group()
exclusive.add_argument("--alpha", nargs="?")
exclusive.add_argument("--beta", nargs="?")
parsed = cli.parse_args()
सुधारे गए संस्करणों में, --alpha --beta चलाने पर सही तरह से “argument --beta: not allowed with argument --alpha” उठता है।
यह क्यों मायने रखता है
कमांड-लाइन इंटरफेस बाधाओं को सुसंगत तरीके से लागू करने पर निर्भर करते हैं। अगर mutually exclusive विकल्प चुपचाप साथ मौजूद रह जाएँ, तो आगे की लॉजिक तक अस्पष्ट कॉन्फ़िगरेशन पहुँच सकता है और व्यवहार अनपेक्षित हो सकता है। अलग-अलग वातावरणों में एक जैसा पार्सर व्यवहार सुनिश्चित करना टूलिंग, CI पाइपलाइनों और प्रोडक्शन वर्कफ़्लोज़ को सूक्ष्म मिसकन्फ़िगरेशन से बचाता है।
nargs='?' पर व्यावहारिक नोट्स
nargs='?' तब सबसे प्रभावी होता है जब इसे स्पष्ट default और const मानों के साथ जोड़ा जाए, जिससे तीन-तरफ़ा अर्थ साफ़ रहें। जब default None रहता है, तो यह तय करना कठिन हो जाता है कि यूज़र ने खाली फ्लैग दिया था या उसे छोड़ा था—जो आगे के निर्णयों को उलझा सकता है।
निष्कर्ष
अगर आप nargs='?' के साथ mutually exclusive समूहों का उपयोग करते हैं, तो सुनिश्चित करें कि आपका रनटाइम Python 3.13.1 या उससे नया हो, ताकि सुधरा हुआ व्यवहार मिले। मंशा स्पष्ट रखने के लिए, optional-value फ्लैग्स डिज़ाइन करते समय default और const तय करें, ताकि “छोड़ा गया” और “खाली” एक जैसे न दिखें। इन बातों का ध्यान रखने से संदिग्ध कमांड लाइनों में समय बचेगा और आपका CLI वैसा ही व्यवहार करेगा जैसा उपयोगकर्ता उम्मीद करते हैं।