python - यह खाली सूची में निर्दिष्ट करने के लिए क्यों मान्य है, लेकिन खाली ट्यूपल के लिए नहीं?




iterable-unpacking (3)

हाल ही में हुए PyCon की बातचीत में यह बात सामने आई।

बयान

[] = []

कुछ भी सार्थक नहीं है, लेकिन यह एक अपवाद भी नहीं फेंकता है। मुझे लग रहा है कि यह अनकैपिंग नियमों के कारण होना चाहिए। आप सूचियों के साथ भी अनप्लगिंग कर सकते हैं, जैसे,

[a, b] = [1, 2]

आप क्या उम्मीद करेंगे। तार्किक परिणाम के रूप में, यह भी काम करना चाहिए, जब अनपैक करने वाले तत्वों की संख्या 0 है, जो यह बताएगी कि खाली सूची में असाइन करना क्यों मान्य है। जब आप खाली सूची में गैर-रिक्त सूची को असाइन करने का प्रयास करते हैं, तो इस सिद्धांत का समर्थन किया जाता है:

>>> [] = [1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack

मुझे इस स्पष्टीकरण से खुशी होगी, अगर वही टुपल्स के लिए भी सही होगा। यदि हम 0 तत्वों के साथ एक सूची में अनपैक कर सकते हैं, तो हमें 0 तत्वों के साथ एक टपल को भी अनपैक करने में सक्षम होना चाहिए, नहीं? हालाँकि:

>>> () = ()
  File "<stdin>", line 1
SyntaxError: can't assign to ()

ऐसा लगता है जैसे ट्यूपल्स के लिए अनपैकिंग नियम लागू नहीं किए गए हैं क्योंकि वे सूचियों के लिए हैं। मैं इस विसंगति के लिए किसी भी स्पष्टीकरण के बारे में नहीं सोच सकता। क्या इस व्यवहार का कोई कारण है?


"एक सूची सौंपना" इसके बारे में सोचने का गलत तरीका है।

सभी मामलों में आप अनपैकिंग कर रहे हैं: पायथन दुभाषिया इसे लिखने के लिए तीनों तरीकों से एक अनपैकिंग निर्देश बनाता है, कोई लिस्ट या टुपल्स बायीं ओर शामिल नहीं होते हैं (कोड शिष्टाचार /u/old-man-prismo ):

>>> def f():
...     iterable = [1, 2]
...     a, b = iterable
...     (c, d) = iterable
...     [e, f] = iterable
...
>>> from dis import dis
>>> dis(f)
  2           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               2 (2)
              6 BUILD_LIST               2
              9 STORE_FAST               0 (iterable)

  3          12 LOAD_FAST                0 (iterable)
             15 UNPACK_SEQUENCE          2
             18 STORE_FAST               1 (a)
             21 STORE_FAST               2 (b)

  4          24 LOAD_FAST                0 (iterable)
             27 UNPACK_SEQUENCE          2
             30 STORE_FAST               3 (c)
             33 STORE_FAST               4 (d)

  5          36 LOAD_FAST                0 (iterable)
             39 UNPACK_SEQUENCE          2
             42 STORE_FAST               5 (e)
             45 STORE_FAST               6 (f)
             48 LOAD_CONST               0 (None)
             51 RETURN_VALUE      

जैसा कि आप देख सकते हैं, तीनों कथन बिल्कुल समान हैं।

अब जो अनपैकिंग करता है वह मूल रूप से है:

_iterator = iter(some_iterable)
a = next(_iterator)
b = next(_iterator)
for superfluous_element in _iterator:
    # this only happens if there’s something left
    raise SyntaxError('Expected some_iterable to have 2 elements')

बाईं ओर अधिक या कम नामों के अनुरूप।

अब जैसा कि @blckknght ने कहा: किसी कारण के लिए कंपाइलर चेक करता है कि बाएं हाथ की तरफ एक खाली टपल है और उसे नापसंद है, लेकिन नहीं तो यह एक खाली सूची है।

यह केवल 0 नामों को निर्दिष्ट करने की अनुमति देने के लिए सुसंगत और तार्किक है: क्यों नहीं? आप मूल रूप से सिर्फ यह दावा करते हैं कि दाहिने हाथ की ओर चलने योग्य खाली है। यह राय bugs.python.org/issue23275 में भी सर्वसम्मति के रूप में उभरती हुई प्रतीत होती है @gecko में उल्लेख किया गया है: चलो अनुमति देते हैं () = iterable


@ User2357112 द्वारा टिप्पणी कि यह संयोग प्रतीत होता है सही प्रतीत होता है। पायथन स्रोत कोड का प्रासंगिक हिस्सा Python/ast.c :

switch (e->kind) {
    # several cases snipped
    case List_kind:
        e->v.List.ctx = ctx;
        s = e->v.List.elts;
        break;
    case Tuple_kind:
        if (asdl_seq_LEN(e->v.Tuple.elts))  {
            e->v.Tuple.ctx = ctx;
            s = e->v.Tuple.elts;
        }
        else {
            expr_name = "()";
        }
        break;
    # several more cases snipped
}
/* Check for error string set by switch */
if (expr_name) {
    char buf[300];
    PyOS_snprintf(buf, sizeof(buf),
                  "can't %s %s",
                  ctx == Store ? "assign to" : "delete",
                  expr_name);
    return ast_error(c, n, buf);
}

tuple s की स्पष्ट जांच है कि लंबाई शून्य नहीं है और जब यह होता है तो एक त्रुटि उठाता है। list ऐसा कोई चेक नहीं है, इसलिए कोई अपवाद नहीं उठाया गया है।

जब किसी खाली टपल को असाइन करने में कोई त्रुटि होती है, तो मुझे किसी खाली सूची में असाइनमेंट की अनुमति देने का कोई विशेष कारण नहीं दिखता है, लेकिन शायद कुछ विशेष मामला है जो मैं विचार नहीं कर रहा हूं। मेरा सुझाव है कि यह संभवतः एक (तुच्छ) बग है और व्यवहार दोनों प्रकार के लिए समान होना चाहिए।


यह एक बग है।

http://bugs.python.org/issue23275

हालांकि, यह हानिरहित प्रतीत होता है इसलिए मुझे संदेह है कि यह काम करने वाले कोड को तोड़ने के डर से तय हो जाएगा।





iterable-unpacking