टप्पल स्लाइसिंग एक नई वस्तु को स्लाइसिंग सूची के विपरीत नहीं लौटाती है


12

पायथन (2 और 3) में। जब भी हम सूची का उपयोग करते हैं, तो यह एक नई वस्तु देता है, जैसे:

l1 = [1,2,3,4]
print(id(l1))
l2 = l1[:]
print(id(l2))

उत्पादन

>>> 140344378384464
>>> 140344378387272

यदि एक ही चीज़ को टपल के साथ दोहराया जाता है, तो वही वस्तु वापस आ जाती है, जैसे:

t1 = (1,2,3,4)
t2 = t1[:]
print(id(t1))
print(id(t2))

उत्पादन

>>> 140344379214896
>>> 140344379214896

यह बहुत अच्छा होगा अगर कोई इस बारे में कुछ प्रकाश डाल सकता है कि ऐसा क्यों हो रहा है, मेरे पाइथन अनुभव के दौरान मैं इस धारणा के तहत था कि खाली स्लाइस एक नई वस्तु देता है।

मेरी समझ यह है कि यह उसी वस्तु को लौटा रहा है जैसे टुपल्स अपरिवर्तनीय हैं और इसकी नई प्रति बनाने का कोई मतलब नहीं है। लेकिन फिर, कहीं भी दस्तावेजों में इसका उल्लेख नहीं किया गया है।



l2 = tuple(iter(l1))अनुकूलन को
दरकिनार

आपके प्रश्न को देखने के बाद गलत तरीके से सी-एप को नोट कियाPyTuple_GetSlice गया। डॉक्स अब ठीक कर दिए गए हैं (यह बीपीओ मुद्दा 38557 था )।
wim

जवाबों:


13

कार्यान्वयन अपरिवर्तनीय प्रकारों के लिए समान उदाहरणों को वापस करने के लिए स्वतंत्र हैं (सीपीथॉन में, आप कभी-कभी तार और पूर्णांक के लिए समान अनुकूलन देख सकते हैं)। चूंकि ऑब्जेक्ट को बदला नहीं जा सकता है, इसलिए उपयोगकर्ता कोड में ऐसा कुछ भी नहीं है जिसे यह ध्यान रखने की आवश्यकता है कि क्या यह एक अद्वितीय उदाहरण या मौजूदा उदाहरण के लिए केवल एक अन्य संदर्भ रखता है।

आप यहां C कोड में शॉर्ट-सर्किट पा सकते हैं ।

static PyObject*
tuplesubscript(PyTupleObject* self, PyObject* item)
{
    ... /* note: irrelevant parts snipped out */
    if (start == 0 && step == 1 &&
                 slicelength == PyTuple_GET_SIZE(self) &&
                 PyTuple_CheckExact(self)) {
            Py_INCREF(self);          /* <--- increase reference count */
            return (PyObject *)self;  /* <--- return another pointer to same */
        }
    ...

यह एक कार्यान्वयन विवरण है, ध्यान दें कि pypy ऐसा नहीं करता है।


धन्यवाद @wim यह अब समझ में आता है। जैसा कि मैं सी में अनुभव नहीं कर रहा हूं, उस विषय से सिर्फ एक चीज। क्या वास्तव में एक-> ob_item करता है? मैंने इसके लिए कोशिश की। लेकिन सब मैं समझ सकता था कि क्या यह "a" का पता लेता है और इसे "ob_item" आगे बढ़ाता है। मेरी समझ ob_item के पास स्टोरेज एड्रेस की संख्या है जो "1" आइटम बनाती है। #offTheTopic
विजय जांगिड़

2
यह यहाँ पर टपल के लिए टाइपफ़ीड को देखने में मदद कर सकता है । तो a->ob_itemऐसा है (*a).ob_item, जैसे कि यह उस सदस्य से बुलाया जाता ob_itemहै PyTupleObjectजो एक ओर इशारा करता है और + ilow तब स्लाइस की शुरुआत के लिए आगे बढ़ता है।
विम

3

यह एक कार्यान्वयन विवरण है। क्योंकि सूचियाँ आपस में जुड़ी हुई हैं , इसलिए उन्हें एक प्रतिलिपि l1[:] अवश्य बनानी चाहिए , क्योंकि आप बदलावों l2को प्रभावित करने की उम्मीद नहीं करेंगे l1

चूँकि एक टूपल अपरिवर्तनीय है , हालाँकि, ऐसा कुछ भी नहीं है जो आप किसी भी दृश्य तरीके से t2प्रभावित कर सकते हैं t1, इसलिए कंपाइलर मुफ़्त है (लेकिन आवश्यक नहीं ) उसी वस्तु का उपयोग करें t1और t1[:]


1

पाइथन में 3. * जहां के my_list[:]लिए वाक्य रचना चीनी है type(my_list).__getitem__(mylist, slice_object): slice_objectएक स्लाइस ऑब्जेक्ट जो कि my_listविशेषता (लंबाई) और अभिव्यक्ति से निर्मित है [:]। इस तरह से व्यवहार करने वाली वस्तुओं को यहां देखे गए पायथन डेटा मॉडल में सबस्क्रिप्टेबल कहा जाता है । सूचियों और टुपल्स के __getitem__लिए एक अंतर्निहित विधि है।

CPython में, और सूचियों और tuples के लिए, __getitem__bytecode ऑपरेशन द्वारा व्याख्या की गई है BINARY_SUBSCRजो यहाँ tuples के लिए और यहाँ सूचियों के लिए कार्यान्वित की गई है

Tuples के मामले में, कोड के माध्यम से चलने आपको लगता है कि में देखेंगे इस कोड को ब्लॉक , static PyObject* tuplesubscript(PyTupleObject* self, PyObject* item)एक ही के लिए एक संदर्भ वापस आ जाएगी PyTupleObjectकि यह इनपुट तर्क के रूप में मिला है, यदि आइटम प्रकार का है PySliceऔर पूरे टपल करने के लिए टुकड़ा मूल्यांकन करता है।

    static PyObject*
    tuplesubscript(PyTupleObject* self, PyObject* item)
    {
        /* checks if item is an index */ 
        if (PyIndex_Check(item)) { 
            ...
        }
        /* else it is a slice */ 
        else if (PySlice_Check(item)) { 
            ...
        /* unpacks the slice into start, stop and step */ 
        if (PySlice_Unpack(item, &start, &stop, &step) < 0) { 
            return NULL;
        }
       ...
        }
        /* if we start at 0, step by 1 and end by the end of the tuple then !! look down */
        else if (start == 0 && step == 1 &&
                 slicelength == PyTuple_GET_SIZE(self) && 
                 PyTuple_CheckExact(self)) {
            Py_INCREF(self); /* increase the reference count for the tuple */
            return (PyObject *)self; /* and return a reference to the same tuple. */
        ...
}

अब आप कोड की जांच करते static PyObject * list_subscript(PyListObject* self, PyObject* item)हैं और अपने लिए देखते हैं कि जो भी टुकड़ा है, एक नई सूची ऑब्जेक्ट हमेशा वापस आ जाती है।


1
ध्यान दें कि यह 2.7 में अलग है , जहां start:stopबिल्ट-इन प्रकार पर एक स्लाइस, सहित tup[:], के माध्यम से नहीं जाता है BINARY_SUBSCR। विस्तारित स्लाइसिंग start:stop:stepसदस्यता के माध्यम से जाती है, यद्यपि।
विम

ठीक है, धन्यवाद अजगर संस्करण को निर्दिष्ट करने के लिए अद्यतन करेगा।
फखर मोकडेम

0

इस बारे में निश्चित नहीं है, लेकिन ऐसा लगता है कि पायथन आपको नकल करने से बचने के लिए उसी वस्तु को एक नया पॉइंटर प्रदान करता है क्योंकि ट्यूपल्स समान हैं (और चूंकि ऑब्जेक्ट टपल है, यह अपरिवर्तनीय है)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.