दोनों 3. और 4. सभी पायथन संस्करणों पर वाक्यविन्यास त्रुटियां होनी चाहिए। हालाँकि आपको एक बग मिल गया है जो पायथन संस्करणों को 2.5 - 3.4 को प्रभावित करता है, और जिसे बाद में पायथन इश्यू ट्रैकर में पोस्ट किया गया । बग की वजह से, एक अपरिवर्तित जनरेटर अभिव्यक्ति को एक फ़ंक्शन के तर्क के रूप में स्वीकार किया गया था यदि यह केवल *args
और / या के साथ था **kwargs
। जबकि पाइथन 2.6+ ने दोनों मामलों को अनुमति दी 3. और 4., पायथन 2.5 ने केवल केस 3 की अनुमति दी - - फिर भी दोनों दस्तावेज व्याकरण के खिलाफ थे :
call ::= primary "(" [argument_list [","]
| expression genexpr_for] ")"
प्रलेखन का कहना है कि एक फ़ंक्शन कॉल में primary
(अभिव्यक्ति जो कॉल करने योग्य का मूल्यांकन करता है) शामिल है, उसके बाद, कोष्ठक में, या तो एक तर्क सूची या बस एक अनिर्धारित जनरेटर अभिव्यक्ति; और तर्क सूची के भीतर, सभी जनरेटर अभिव्यक्तियाँ कोष्ठक में होनी चाहिए।
यह बग (हालांकि ऐसा लगता है कि यह ज्ञात नहीं था), पायथन 3.5 प्रीरेलिस में तय किया गया था। पायथन में 3.5 कोष्ठक हमेशा एक जनरेटर अभिव्यक्ति के आसपास आवश्यक होते हैं, जब तक कि यह फ़ंक्शन का एकमात्र तर्क नहीं है:
Python 3.5.0a4+ (default:a3f2b171b765, May 19 2015, 16:14:41)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f(1 for i in [42], *a)
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
यह अब Python 3.5 में व्हाट्स न्यू में प्रलेखित है , इस बग को चिह्नित करने के लिए DeTeReR का धन्यवाद।
बग का विश्लेषण
पायथन 2.6 में एक परिवर्तन किया गया था जिसके बाद खोजशब्द तर्क के उपयोग की अनुमति दी गई *args
:
किसी फ़ंक्शन कॉल के लिए * args तर्क के बाद कीवर्ड तर्क प्रदान करना कानूनी हो गया है।
>>> def f(*args, **kw):
... print args, kw
...
>>> f(1,2,3, *(4,5,6), keyword=13)
(1, 2, 3, 4, 5, 6) {'keyword': 13}
पहले यह एक सिंटैक्स त्रुटि होती। (अमौरी फोर्जोट डी आर्क द्वारा योगदान; मुद्दा 3473।)
हालाँकि, पायथन 2.6 व्याकरण कीवर्ड तर्क, स्थिति तर्क, या नंगे जनरेटर के भावों के बीच कोई अंतर नहीं करता है - वे सभी प्रकार argument
के पार्सर हैं।
पायथन नियमों के अनुसार, यदि यह फ़ंक्शन का एकमात्र तर्क नहीं है, तो एक जनरेटर अभिव्यक्ति को छोटा किया जाना चाहिए। इसमें मान्य है Python/ast.c
:
for (i = 0; i < NCH(n); i++) {
node *ch = CHILD(n, i);
if (TYPE(ch) == argument) {
if (NCH(ch) == 1)
nargs++;
else if (TYPE(CHILD(ch, 1)) == gen_for)
ngens++;
else
nkeywords++;
}
}
if (ngens > 1 || (ngens && (nargs || nkeywords))) {
ast_error(n, "Generator expression must be parenthesized "
"if not sole argument");
return NULL;
}
हालांकि यह फ़ंक्शन बिल्कुल भी विचार नहीं करता है *args
- यह विशेष रूप से केवल सामान्य स्थिति संबंधी तर्क और कीवर्ड तर्क के लिए दिखता है।
उसी फ़ंक्शन में नीचे, कीवर्ड arg के बाद गैर-कीवर्ड arg के लिए एक त्रुटि संदेश उत्पन्न होता है :
if (TYPE(ch) == argument) {
expr_ty e;
if (NCH(ch) == 1) {
if (nkeywords) {
ast_error(CHILD(ch, 0),
"non-keyword arg after keyword arg");
return NULL;
}
...
लेकिन यह फिर से उन दलीलों पर लागू होता है जो कथन द्वारा प्रमाण के रूप में अनपेक्षित रूप से जनरेटर के भाव नहीं हैं :else if
else if (TYPE(CHILD(ch, 1)) == gen_for) {
e = ast_for_genexp(c, ch);
if (!e)
return NULL;
asdl_seq_SET(args, nargs++, e);
}
इस प्रकार एक अपरिवर्तित जनरेटर अभिव्यक्ति को पास करने की अनुमति दी गई थी।
अब पायथन 3.5 *args
में एक फ़ंक्शन कॉल में कहीं भी उपयोग किया जा सकता है , इसलिए इसके लिए समायोजित करने के लिए व्याकरण को बदल दिया गया था:
arglist: argument (',' argument)* [',']
तथा
argument: ( test [comp_for] |
test '=' test |
'**' test |
'*' test )
और for
पाश बदल गया था करने के लिए
for (i = 0; i < NCH(n); i++) {
node *ch = CHILD(n, i);
if (TYPE(ch) == argument) {
if (NCH(ch) == 1)
nargs++;
else if (TYPE(CHILD(ch, 1)) == comp_for)
ngens++;
else if (TYPE(CHILD(ch, 0)) == STAR)
nargs++;
else
/* TYPE(CHILD(ch, 0)) == DOUBLESTAR or keyword argument */
nkeywords++;
}
}
इस प्रकार बग को ठीक करना।
हालांकि अनजाने में बदलाव वैध वैध निर्माण है
func(i for i in [42], *args)
तथा
func(i for i in [42], **kwargs)
जहां एक अपरिवर्तित जनरेटर पहले से काम करता है *args
या **kwargs
अब काम करना बंद कर देता है।
इस बग का पता लगाने के लिए, मैंने विभिन्न पायथन संस्करणों की कोशिश की। 2.5 में आपको मिलेगा SyntaxError
:
Python 2.5.5 (r255:77872, Nov 28 2010, 16:43:48)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f(*[1], 2 for x in [2])
File "<stdin>", line 1
f(*[1], 2 for x in [2])
और यह पायथन 3.5 के कुछ पूर्वगामी से पहले तय किया गया था:
Python 3.5.0a4+ (default:a3f2b171b765, May 19 2015, 16:14:41)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f(*[1], 2 for x in [2])
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
हालाँकि, पैरेंटाइज़्ड जनरेटर एक्सप्रेशन, यह पायथन 3.5 में काम करता है, लेकिन यह पायथन 3.4 में काम नहीं करता है:
f(*[1], (2 for x in [2]))
और यह सुराग है। पायथन 3.5 में *splatting
सामान्यीकृत है; आप इसे फंक्शन कॉल में कहीं भी उपयोग कर सकते हैं:
>>> print(*range(5), 42)
0 1 2 3 4 42
तो वास्तविक बग ( *star
कोष्ठकों के बिना काम करने वाला जनरेटर ) वास्तव में अजगर 3.5 में तय किया गया था , और बग में पाया जा सकता है कि पायथन 3.4 और 3.5 के बीच क्या बदल गया है