2011-10-06 20 views
29

पायथन में एक अनंत नेस्टेड सूची बनाना संभव है। यह स्पष्ट है और, हालांकि लोकप्रिय नहीं है और निश्चित रूप से उपयोगी नहीं है एक ज्ञात तथ्य है।असीमित नेस्टेड सूचियों में वास्तव में क्या हो रहा है?

>>> a = [0] 
>>> a[0] = a 
>>> a 
[[...]] 
>>> a[0] == a 
True 

मेरा प्रश्न है, यहाँ क्या हो रहा है:

>>> a = [0] 
>>> b = [0] 
>>> a[0], b[0] = b, a 
>>> a 
[[[...]]] 
>>> b 
[[[...]]] 
>>> a == b 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
RuntimeError: maximum recursion depth exceeded in cmp 
>>> a[0] == b 
True 
>>> a[0][0] == b 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
RuntimeError: maximum recursion depth exceeded in cmp 
>>> a[0][0][0] == b 
True 
>>> 

कौन सा हर तरह गहरा है, जब मैं इसे समझने की कोशिश कर रहा हूँ, मैं और अधिक लग रहा है मेरे मस्तिष्क की तरह विस्फोट के लिए जा रहा है। मैं देखता हूं, जिसमें एक बी है, जिसमें एक और इतने पर ...

अब इस बारे में मेरे प्रश्न हैं। क्या हमारे पास वास्तव में यहां दो सूचियां हैं, या केवल एक? इस तरह की चीज स्मृति में कैसे संग्रहीत होती है? कार्यक्रमकों को इस तरह के कुछ अजीब को लागू करने के लिए एक उद्देश्य क्या हो सकता है?

कृपया, इस सवाल का इलाज बहुत गंभीर नहीं है। और मत भूलना, प्रोग्रामिंग कभी-कभी मजेदार हो सकती है।

+1

वास्तव में एक मजेदार सुविधा है यही कारण है कि। – phimuemue

+0

बहुत बढ़िया सवाल। मुझे वास्तव में पाइथन की यह सुविधा पसंद है, हालांकि मुझे इसके लिए कभी भी इसका उपयोग नहीं मिला है। यह बहुत अच्छा होगा अगर कोई इस सुविधा के व्यावहारिक अनुप्रयोग के साथ आ सकता है। – andronikus

+1

@andronikus पी: http://xkcd.com/468/ –

उत्तर

24

अस्वीकरण: मैं अजगर का उपयोग नहीं करते हैं, तो कुछ बातें मैं कहता हूँ गलत हो सकता है। पायथन विशेषज्ञ, मुझे सही करने के लिए स्वतंत्र महसूस करें।

शानदार सवाल। मैं केंद्रीय ग़लतफ़हमी लगता है; आपको लगता है कि सवाल पूछने के लिए संकेत देता हो रही हो, (यदि मैं भी ऐसा लगता है कि फोन नहीं कर सकते हैं कि यह कैसे आप विचार प्रक्रिया आप के लिए इस्तेमाल किया पर पहुंचे पूरी तरह से उचित है) इस है:

जब मैं b[0] = a लिखता हूं, तो इसका मतलब यह नहीं है कि ab में है। इसका मतलब है कि b में एक संदर्भ शामिल है जो a अंकों के लिए इंगित करता है।

चर a और b स्वयं भी "चीजें" स्वयं नहीं हैं, और वे स्वयं स्मृति में अन्यथा अज्ञात "चीजें" के संकेतक भी हैं।

संदर्भ की अवधारणा गैर प्रोग्रामिंग की दुनिया से एक प्रमुख छलांग है, इसलिए के मन में इस के साथ अपने कार्यक्रम के माध्यम से कदम हैं:

>>> a = [0] 

आप एक सूची है कि यह में कुछ है करने के लिए होता बनाने (उपेक्षा अब के लिए)। क्या मायने रखता है यह एक सूची है। वह सूची स्मृति में संग्रहीत हो जाती है। आइए मान लें कि यह स्मृति स्थान 1001 में संग्रहीत है। फिर, असाइनमेंट = एक चर a बनाता है जो प्रोग्रामिंग भाषा आपको बाद में उपयोग करने की अनुमति देती है। इस बिंदु पर, स्मृति में कुछ सूची वस्तु है और इसके संदर्भ में आप a नाम से पहुंच सकते हैं।

>>> b = [0] 

यह b के लिए एक ही बात है। एक नई सूची है जो स्मृति स्थान 1002 में संग्रहीत हो जाती है। प्रोग्रामिंग भाषा एक संदर्भ b बनाता है जिसका उपयोग आप स्मृति स्थान और सूची ऑब्जेक्ट को संदर्भित करने के लिए कर सकते हैं।a[0] = b:

>>> a[0], b[0] = b, a 

यह दो चीजें हैं जो समान हैं, तो चलो एक पर ध्यान केंद्रित करते है। यह क्या करता है सुंदर फैंसी है। यह पहले समानता के दाहिने तरफ का मूल्यांकन करता है, परिवर्तनीय b देखता है और b के बाद से संबंधित वस्तु को मेमोरी (मेमोरी ऑब्जेक्ट # 1002) में लाता है। बाईं तरफ क्या होता है उतना ही फैंसी है। a एक चर है जो एक सूची (मेमोरी ऑब्जेक्ट # 1001) को इंगित करता है, लेकिन मेमोरी ऑब्जेक्ट # 1001 में स्वयं के कई संदर्भ हैं। उन संदर्भों के बजाय जिनके नाम a और b हैं, जिनका उपयोग आप करते हैं, उन संदर्भों में 0 जैसे संख्यात्मक सूचकांक हैं। तो, अब, यह क्या करता है a मेमोरी ऑब्जेक्ट # 1001 खींचता है, जो अनुक्रमित संदर्भों का ढेर है, और यह इंडेक्स 0 के संदर्भ में जाता है (पहले, यह संदर्भ वास्तविक संख्या 0 पर इंगित करता है, जो आपने किया है लाइन 1 में) और उसके बाद उस संदर्भ को संदर्भित करता है (यानी, मेमोरी ऑब्जेक्ट # 1001 में पहला और एकमात्र संदर्भ) समीकरण के दाहिने तरफ की चीज़ का मूल्यांकन करने के लिए क्या होता है। तो अब, # 1002 ऑब्जेक्ट करने के लिए # 1001 के 0 वें संदर्भ बिंदु ऑब्जेक्ट करें।

>>> a 
[[[...]]] 
>>> b 
[[[...]]] 

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

>>> a == b 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
RuntimeError: maximum recursion depth exceeded in cmp 

इस कथन की विफलता के साथ यह करना है कि पायथन तुलना कैसे करता है। जब आप किसी ऑब्जेक्ट की तुलना अपने आप करते हैं, तो यह तुरंत सत्य का मूल्यांकन करता है। जब आप किसी अन्य ऑब्जेक्ट की तुलना और ऑब्जेक्ट करते हैं, तो यह निर्धारित करने के लिए "जादू" का उपयोग करता है कि समानता सत्य या गलत होनी चाहिए या नहीं। पायथन में सूचियों के मामले में, यह प्रत्येक सूची में प्रत्येक आइटम को देखता है और चेक करता है कि वे बराबर हैं (बदले में आइटम की अपनी समानता-जांच विधियों का उपयोग करके)। तो, जब आप a == b आज़माते हैं। यह क्या करता है सबसे पहले बी (ऑब्जेक्ट # 1002) और एक (ऑब्जेक्ट # 1001) खोदता है और फिर यह महसूस करता है कि वे स्मृति में अलग-अलग चीजें हैं, इसलिए इसकी रिकर्सिव सूची चेकर पर जाती है। यह दो सूचियों के माध्यम से पुनरावृत्ति द्वारा करता है। ऑब्जेक्ट # 1001 में इंडेक्स 0 वाला एक तत्व है जो ऑब्जेक्ट # 1002 पर इंगित करता है। ऑब्जेक्ट # 1002 में इंडेक्स 0 वाला एक तत्व है जो ऑब्जेक्ट # 1001 पर इंगित करता है। इसलिए, कार्यक्रम निष्कर्ष निकाला है कि ऑब्जेक्ट # 1001 और # 1002 बराबर हैं यदि उनके सभी संदर्भ एक ही चीज़ पर इंगित करते हैं, तो # 1002 (क्या # 1001 का केवल संदर्भ बिंदु) और # 1001 (क्या # 1002 का संदर्भ संदर्भ) हैं। वही चीज़। यह समानता जांच कभी नहीं रुक सकती है। वही बात किसी भी सूची में होती है जो रुकती नहीं है। आप c = [0]; d = [0]; c[0] = d; d[0] = c और a == c कर सकते हैं एक ही त्रुटि उठाएंगे।

>>> a[0] == b 
True 

जैसा कि मैंने पिछले अनुच्छेद में संकेत दिया है, यह तुरंत सत्य साबित होता है क्योंकि पायथन एक शॉर्टकट लेता है। सूची सूची की तुलना करने की आवश्यकता नहीं है क्योंकि a[0] ऑब्जेक्ट # 1002 और b ऑब्जेक्ट्स # 1002 पर ऑब्जेक्ट करने के लिए अंक। पायथन का पता चलता है कि वे शाब्दिक अर्थ में समान हैं (वे वही "चीज" हैं) और जांच सामग्री को भी परेशान नहीं करते हैं।

>>> a[0][0] == b 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
RuntimeError: maximum recursion depth exceeded in cmp 

इसका कारण यह है a[0][0] संख्या 1001 वस्तु की ओर इशारा करते समाप्त होता है एक त्रुटि होने के लिए वापस चला जाता है। पहचान जांच विफल हो जाती है और रिकर्सिव सामग्री जांच पर वापस आती है, जो कभी खत्म नहीं होती है।

>>> a[0][0][0] == b 
True 

एक बार फिर, a[0][0][0] अंक संख्या 1002 आपत्ति उठाने, b करता है। रिकर्सिव चेक छोड़ दिया गया है और तुलना तुरंत सच हो जाती है।


उच्चतर स्तर अड़ियल घोड़ा अस्पष्ट नहीं सीधे अपने विशिष्ट कोड का टुकड़ा से संबंधित:

  • सब वहाँ है के बाद से, अन्य वस्तुओं की चर्चा करते हुए संदर्भ है, भले ही क्या है "अनंत" नेस्टिंग प्रतीत होता है, वस्तु a से संबोधित किया जाता है (जैसा कि मैं वस्तु संख्या 1001 कहा जाता है) और वस्तु होने की b (संख्या 1002) स्मृति में दोनों एक ही आकार के होते हैं कहा जाता है। और वह आकार वास्तव में अविश्वसनीय रूप से छोटा है क्योंकि वे सभी सूचियां हैं जो संबंधित अन्य स्मृति स्थानों को इंगित करती हैं।
  • यह भी लायक ध्यान दें कि कम "उदार" भाषाओं में, == रिटर्न trueकेवल यदि उनके द्वारा इंगित स्मृति वस्तुओं अर्थ है कि दोनों संदर्भों को स्मृति में उसी जगह को इंगित में ही कर रहे हैं के साथ दो संदर्भों की तुलना है। जावा इसका एक उदाहरण है। शैलीगत परंपरा है कि इस तरह के भाषाओं में उभरा है (जावा के लिए, यह पारंपरिक equals() कहा जाता है) खुद वस्तुओं पर एक विधि/समारोह को परिभाषित करने के लिए कस्टम समानता परीक्षण करना है। पाइथन इसे सूचियों के लिए बॉक्स से बाहर करता है। मैं विशेष रूप से अजगर के बारे में पता नहीं है, लेकिन रूबी में कम से कम, == है कि जब आप someobject == otherobject करते हैं, यह वास्तव में एक विधि ==someobject पर (है कि आप अधिलेखित कर सकते हैं) कहा जाता कॉल अर्थ में ओवरलोड हो गया है। सिद्धांत रूप में, आपको someobject == otherobject बनाने से रोकने के लिए कुछ भी नहीं होगा जो बूलियन के अलावा कुछ और लौटाता है।
+0

ग्रेट उत्तर। वास्तव में, मैं और कुछ भी नहीं कर सकता, बस इसे स्वीकार करें। एक अच्छा और विस्तृत उत्तर के लिए – Gandi

+0

+1। एकमात्र चीज जिसे मैं संभवतः शिकायत कर सकता हूं वह यह है कि '[0]' को पायथन में * सूची * कहा जाता है, न कि * सरणी *। वहाँ भी हैं [arrays] (http://docs.python.org/library/array.html), लेकिन वे सूचियों के संदर्भ में चक्रीय संदर्भों की सुविधा नहीं देते हैं। –

+0

@ स्वेनमार्कैच: इसे इंगित करने के लिए धन्यवाद। मैं एक त्वरित संपादन में डाल दूंगा ताकि भविष्य में लोग भ्रमित न हों। सरणी चक्रीय संदर्भों का समर्थन क्यों नहीं करते? क्या वे पुन: असाइनमेंट या कुछ पर क्लोन हो जाते हैं? –

11

मैं संदिग्ध निम्न होता है:

a[0]==b: अजगर मूल्य a[0] ऊपर लग रहा है और b के संदर्भ में किसी तरह का पाता है, तो यह True कहते हैं।

a[0][0]==b: अजगर a[0] को देखता है, b पाता है और अब a[0][0] को देखता है, जो, है (के बाद से a[0] रखती b) b[0]। अब यह देखता है कि b[0]a पर किसी प्रकार का संदर्भ रखता है, जो बिल्कुल b जैसा नहीं है। इसलिए अजगर को तत्वों की तुलना करना है, जिसका अर्थ है, इसे की तुलना b[0] के साथ करना है। अब, अनंत रिकर्सन शुरू होता है ...

ध्यान दें कि यह केवल इसलिए काम करता है क्योंकि a[0]=b असाइन करते समय पायथन वास्तव में सूची की प्रतिलिपि नहीं बनाते हैं। पाइथन b का संदर्भ बनाता है जो a[0] में संग्रहीत है।

+0

यह एक अच्छा स्पष्टीकरण है। मुझे लगता है, मैं इसे समझना शुरू कर रहा हूँ। – Gandi

4

ये दो सूचियां हैं। सबसे पहले, आप उन्हें बनाने:

a = [0] 
b = [0] 

और फिर, आप एक दूसरे के पहले तत्व के लिए हर एक को आवंटित:

a[0], b[0] = b, a 

तो आप कह सकते हैं

a[0] is b 

और

b[0] is a 

जो एक ही स्थिति है आयन पहले उदाहरण के रूप में, लेकिन ओबे स्तर गहरा।

इसके अतिरिक्त, आप पहचान (is) की तुलना नहीं करते हैं, लेकिन समानता (==) के लिए तुलना नहीं करते हैं। इससे उनकी तुलना करने की कोशिश की जाती है - गहराई से अंदर, जो एक पुनरावर्तन की ओर जाता है।

+0

'is' के साथ अच्छी बात है। मैंने इस तरह की तुलना करने के बारे में नहीं सोचा था। – Gandi

7

मैं देख रहा हूँ, कि एक ख, कि एक

वे इस तरह के रूप में एक दूसरे शामिल नहीं है शामिल होते हैं - एक एक सूची के लिए एक संदर्भ है, इस सूची में पहली बात एक संदर्भ है बी, और करने के लिए इसके विपरीत

>>> a[0] == b 
True 
>>> a[0][0] == b 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
RuntimeError: maximum recursion depth exceeded in cmp 
>>> a[0][0][0] == b 
True 

की संख्या [0] 'यहाँ है कोई फर्क नहीं पड़ता, के रूप में आप की तरह के रूप में आप के रूप में कई सूची लुकअप कर सकते हैं - क्या मायने रखती है कि # 1 उदाहरण और # में 3 (और लुकअप की सभी विषम संख्याएं) आप कह रहे हैं "बी बी बराबर बी है", जिस बिंदु पर पायथन स्मृति पते की तुलना करता है और देखता है कि वे एक ही बात हैं, इसलिए हां कहते हैं। उदाहरण के साथ # 2 (और सभी लुकअप) आप कह रहे हैं "बी बराबर बी है", पायथन देखता है कि वे अलग-अलग मेमोरी पते हैं, और फिर संपूर्ण (अनंत) डेटा संरचना को स्मृति में लोड करने का प्रयास करते हैं ताकि अधिक इन- गहराई की तुलना।

10

a[0]b और b[0] को संदर्भित करता है a। यह एक परिपत्र संदर्भ है। जैसा कि glglgl ने उल्लेख किया है, जब आप == ऑपरेटर को आजमाते हैं तो यह मानों की तुलना करने की कोशिश करता है।

इस प्रयास करें, जो चीजों को और अधिक स्पष्ट कर सकता है -

>>> id(a) 
4299818696 
>>> id(b) 
4299818768 
>>> id(a[0]) 
4299818768 
>>> 
>>> id(b[0]) 
4299818696 
+2

यह एक अच्छा जवाब है। यह बहुत सरल बताता है, दोनों सूचियों को कैसे संग्रहीत किया जाता है। – Gandi

संबंधित मुद्दे