सवाल पायथन में एक गैर-निर्दिष्ट स्ट्रिंग मेमोरी में एक पता कैसे हो सकता है?


क्या कोई मुझे ये समझा सकता है? तो मैं पाइथन में आईडी () कमांड के साथ खेल रहा हूं और इस पर आया:

>>> id('cat')
5181152
>>> a = 'cat'
>>> b = 'cat'
>>> id(a)
5181152
>>> id(b)
5181152

यह एक भाग को छोड़कर मुझे कुछ समझ में आता है: स्ट्रिंग 'बिल्ली' को एक चर के लिए आवंटित करने से पहले स्मृति में एक पता है। मैं शायद समझ में नहीं आता कि मेमोरी एड्रेसिंग कैसे काम करती है लेकिन क्या कोई मुझे यह समझा सकता है या कम से कम मुझे बता सकता है कि मुझे मेमोरी एड्रेसिंग पर पढ़ना चाहिए?

तो यह सब ठीक है और अच्छा है लेकिन यह मुझे आगे उलझन में डाल दिया:

>>> a = a[0:2]+'t'
>>> a
'cat'
>>> id(a)
39964224
>>> id('cat')
5181152

यह मुझे अजीब के रूप में मारा क्योंकि 'बिल्ली' 5181152 के पते के साथ एक स्ट्रिंग है लेकिन नया  एक अलग पता है। तो अगर दो हैं 'बिल्ली' स्मृति में तार क्यों दो पते मुद्रित नहीं हैं आईडी ( 'बिल्ली')? मेरा आखिरी विचार यह था कि सम्मेलन में पते में परिवर्तन के साथ कुछ करना था इसलिए मैंने यह कोशिश की:

>>> id(b[0:2]+'t')
39921024
>>> b = b[0:2]+'t'
>>> b
'cat'
>>> id(b)
40000896

मैंने आईडी को एक जैसा होने की भविष्यवाणी की होगी लेकिन यह मामला नहीं था। विचार?


44
2017-08-03 19:07


मूल


यह भी देखें stackoverflow.com/questions/2519580/... - Zan Lynx
तथा stackoverflow.com/questions/1136826/... - Zan Lynx
तथा stackoverflow.com/questions/1664840/... - Zan Lynx
और अधिक: stackoverflow.com/questions/1504717/... - Zan Lynx
व्ही! stackoverflow.com/questions/1216259/... - Zan Lynx


जवाब:


पायथन स्ट्रिंग अक्षर का काफी आक्रामक रूप से उपयोग करता है। जिन नियमों से यह करता है वे कार्यान्वयन-निर्भर होते हैं, लेकिन सीपीथन दो का उपयोग करता है जो मुझे पता है:

  • स्ट्रिंग्स जिनमें केवल पाइथन पहचानकर्ताओं में मान्य वर्ण हैं प्रशिक्षु, जिसका अर्थ है कि वे एक बड़ी मेज में संग्रहित होते हैं और जहां भी वे होते हैं उनका पुन: उपयोग किया जाता है। तो, कोई फर्क नहीं पड़ता कि आप कहां उपयोग करते हैं "cat", यह हमेशा एक ही स्ट्रिंग ऑब्जेक्ट को संदर्भित करता है।
  • एक ही कोड ब्लॉक में स्ट्रिंग अक्षर को उनकी सामग्री और लंबाई के बावजूद पुन: उपयोग किया जाता है। यदि आप एक समारोह में पूरे गेटिसबर्ग पता का एक स्ट्रिंग अक्षर डालते हैं, तो दो बार, यह एक ही स्ट्रिंग ऑब्जेक्ट दोनों बार होता है। अलग-अलग कार्यों में, वे अलग-अलग वस्तुएं हैं: def foo(): return "pack my box with five dozen liquor jugs" def bar(): return "pack my box with five dozen liquor jugs" assert foo() is bar() # AssertionError

दोनों ऑप्टिमाइज़ेशन संकलन समय पर किए जाते हैं (यानी, जब बाइटकोड उत्पन्न होता है)।

दूसरी ओर, कुछ पसंद है chr(99) + chr(97) + chr(116) एक स्ट्रिंग है अभिव्यक्ति जो स्ट्रिंग का मूल्यांकन करता है "cat"। पाइथन जैसे गतिशील भाषा में, इसका मान संकलन समय पर ज्ञात नहीं किया जा सकता है (chr() एक अंतर्निहित फ़ंक्शन है, लेकिन आपने इसे फिर से सौंप दिया होगा) इसलिए यह आमतौर पर इंटर्न नहीं किया जाता है। इस प्रकार यह id() उस से अलग है "cat"। हालांकि, आप एक स्ट्रिंग को प्रशिक्षित करने के लिए मजबूर कर सकते हैं intern() समारोह। इस प्रकार:

id(intern(chr(99) + chr(97) + chr(116))) == id("cat")   # True

जैसा कि अन्य ने उल्लेख किया है, इंटर्निंग संभव है क्योंकि तार अपरिवर्तनीय हैं। बदलना संभव नहीं है "cat" सेवा मेरे "dog", दूसरे शब्दों में। आपको एक नई स्ट्रिंग ऑब्जेक्ट उत्पन्न करना है, जिसका अर्थ है कि कोई खतरा नहीं है कि एक ही स्ट्रिंग को इंगित करने वाले अन्य नाम प्रभावित होंगे।

एक तरफ के रूप में, पायथन भी अभिव्यक्तियों को परिवर्तित करता है जिसमें केवल स्थिरांक होते हैं (जैसे "c" + "a" + "t") संकलन समय पर स्थिरांक के लिए, जैसा कि नीचे disassembly दिखाता है। इन्हें ऊपर दिए गए नियमों के अनुसार समान स्ट्रिंग ऑब्जेक्ट्स को इंगित करने के लिए अनुकूलित किया जाएगा।

>>> def foo(): "c" + "a" + "t"
...
>>> from dis import dis; dis(foo)
  1           0 LOAD_CONST               5 ('cat')
              3 POP_TOP
              4 LOAD_CONST               0 (None)
              7 RETURN_VALUE

52
2017-08-03 19:29



वाह, बधाई, उन सोने के बैज आने के लिए मुश्किल हैं! इसके अलावा, मैंने गेटिसबर्ग एड्रेस के स्ट्रिंग अक्षरशः कोशिश की और पायथन ने इसे प्रशिक्षित किया, इसलिए मुझे पूरा यकीन है कि यह बेहद आक्रामक तरीके से करता है। - kindall
पायथन इंटर्न नहीं करता है सब स्ट्रिंग अक्षर। कौन सा इंटर्न किया गया है एक कार्यान्वयन विस्तार है, लेकिन मेरा मानना ​​है कि व्यवहार करना है इंटर्न स्ट्रिंग अक्षर जिसमें केवल वर्ण होते हैं जो पाइथन पहचानकर्ता में दिखाई दे सकते हैं। अगर ऐसा लगता है कि गेटिसबर्ग पता प्रशिक्षित किया गया था, तो शायद यह एक था असंबंधित लेकिन बहुत समान अनुकूलन। - user2357112
यह तो बहुत ही मज़ेदार है! - kindall
इस नई जानकारी को व्यक्त करने के लिए अद्यतन किया गया। - kindall


'cat' एक पता है क्योंकि आप इसे पास करने के लिए इसे बनाते हैं id()। आपने अभी तक इसे किसी नाम पर बाध्य नहीं किया है, लेकिन ऑब्जेक्ट अभी भी मौजूद है।

अजगर कैश और छोटे तारों का पुन: उपयोग करता है। लेकिन यदि आप concatenation द्वारा तारों को इकट्ठा करते हैं, तो कोड जो कैश की खोज करता है और फिर से उपयोग करने का प्रयास करता है उसे छोड़ दिया जाता है।

ध्यान दें कि स्ट्रिंग कैश की आंतरिक कार्यप्रणाली शुद्ध कार्यान्वयन विस्तार है और इस पर भरोसा नहीं किया जाना चाहिए।


47
2017-08-03 19:11





सभी मान स्मृति में कहीं भी रहना चाहिए। इसलिए id('cat') एक मूल्य पैदा करता है। आप इसे "अस्तित्वहीन" स्ट्रिंग कहते हैं, लेकिन यह स्पष्ट रूप से मौजूद है, इसे अभी तक किसी नाम पर असाइन नहीं किया गया है।

स्ट्रिंग्स अपरिवर्तनीय हैं, इसलिए दुभाषिया चालाक चीजें कर सकता है जैसे शाब्दिक के सभी उदाहरण बनाते हैं 'cat' वही वस्तु हो, ताकि वह हो id(a) तथा id(b) समान हैं।

तारों पर संचालन नए तारों का उत्पादन करेगा। ये वही सामग्री के साथ पिछले तारों के समान स्ट्रिंग्स हो सकते हैं या नहीं भी हो सकते हैं।

ध्यान दें कि ये सभी विवरण सीपीथॉन के कार्यान्वयन विवरण हैं, और वे किसी भी समय बदल सकते हैं। आपको वास्तविक कार्यक्रमों में इन मुद्दों से चिंतित होने की आवश्यकता नहीं है।


17
2017-08-03 19:13





पाइथन चर अन्य भाषाओं में चर के विपरीत हैं (कहें, सी)।

कई अन्य भाषाओं में, एक चर मेमोरी में किसी स्थान के लिए एक नाम है। इन भाषाओं में, विभिन्न प्रकार के चर विभिन्न प्रकार के स्थानों को संदर्भित कर सकते हैं, और उसी स्थान को कई नाम दिए जा सकते हैं। अधिकांश भाग के लिए, समय-समय पर दिए गए स्मृति स्थान में डेटा परिवर्तन हो सकता है। अप्रत्यक्ष रूप से स्मृति स्थानों को संदर्भित करने के तरीके भी हैं (int *p उस पते पर पता, और स्मृति स्थान में, एक पूर्णांक होगा।) लेकिन वास्तविक स्थान एक परिवर्तनीय संदर्भ बदल नहीं सकता है; चर है स्थान। इन भाषाओं में एक परिवर्तनीय असाइनमेंट प्रभावी रूप से "इस चर के लिए स्थान देखें, और इस डेटा को उस स्थान पर कॉपी करें"

पाइथन इस तरह से काम नहीं करता है। पायथन में, वास्तविक वस्तुएं कुछ स्मृति स्थान पर जाती हैं, और चर स्थान के लिए टैग की तरह होते हैं। पाइथन संग्रहित मानों को एक अलग तरीके से प्रबंधित करता है कि यह चर को कैसे प्रबंधित करता है। अनिवार्य रूप से, पायथन में एक असाइनमेंट का अर्थ है "इस चर के लिए जानकारी देखें, उस स्थान को भूल जाएं जो पहले से ही संदर्भित है, और इसे इस नए स्थान से प्रतिस्थापित करें"। कोई डेटा कॉपी नहीं किया गया है।

लंगुग्स की एक आम विशेषता जो कि अजगर की तरह काम करती है (जैसा कि पहले प्रकार के विपरीत हम पहले के बारे में बात कर रहे थे) यह है कि कुछ प्रकार की वस्तुओं को विशेष तरीके से प्रबंधित किया जाता है; समान मान कैश किए जाते हैं ताकि वे अतिरिक्त मेमोरी न लें, और ताकि उनकी तुलना बहुत आसानी से की जा सके (यदि उनके पास एक ही पता है, तो वे बराबर हैं)। इस प्रक्रिया को बुलाया जाता है होना शामिल; सभी पायथन स्ट्रिंग अक्षरों को प्रशिक्षित किया जाता है (कुछ अन्य प्रकारों के अलावा), हालांकि गतिशील रूप से बनाए गए स्ट्रिंग्स नहीं हो सकते हैं।

आपके सटीक कोड में, अर्थपूर्ण संवाद होगा:

# before anything, since 'cat' is a literal constant, add it to the intern cache
>>> id('cat') # grab the constant 'cat' from the intern cache and look up 
              # it's address
5181152
>>> a = 'cat' # grab the constant 'cat' from the intern cache and 
              # make the variable "a" point to it's location 
>>> b = 'cat' # do the same thing with the variable "b"
>>> id(a) # look up the object "a" currently points to, 
          # then look up that object's address
5181152
>>> id(b) # look up the object "b" currently points to, 
          # then look up that object's address
5181152

8
2017-08-03 19:39





आपके द्वारा पोस्ट किया गया कोड इंटरमीडिएट ऑब्जेक्ट्स के रूप में नए स्ट्रिंग बनाता है। इन बनाए गए तारों में अंततः आपके मूल के समान सामग्री होती है। मध्यवर्ती समयावधि में, वे मूल रूप से मूल रूप से मेल नहीं खाते हैं, और उन्हें एक अलग पते पर रखा जाना चाहिए।

>>> id('cat')
5181152

जैसा कि दूसरों ने उत्तर दिया है, इन निर्देशों को जारी करके, आप पाइथन वीएम को "बिल्ली" स्ट्रिंग वाली स्ट्रिंग ऑब्जेक्ट बनाने के लिए कारण बनाते हैं। यह स्ट्रिंग ऑब्जेक्ट कैश किया गया है और पता 5181152 पर है।

>>> a = 'cat'
>>> id(a)
5181152

दोबारा, इस कैश किए गए स्ट्रिंग ऑब्जेक्ट को 5181152 पर "बिल्ली" युक्त संदर्भित करने के लिए असाइन किया गया है।

>>> a = a[0:2]
>>> id(a)
27731511

इस बिंदु पर आपके प्रोग्राम के संशोधित संस्करण में, आपने दो छोटी स्ट्रिंग ऑब्जेक्ट्स बनाई हैं: 'cat' तथा 'ca''cat' अभी भी कैश में मौजूद है। जिस स्ट्रिंग को a संदर्भ एक अलग और संभवतः उपन्यास स्ट्रिंग ऑब्जेक्ट है, जिसमें वर्ण हैं 'ca'

>>> a = a + 't'
>>> id(a)
39964224

अब आपने एक और नई स्ट्रिंग ऑब्जेक्ट बनाई है। यह वस्तु स्ट्रिंग का समापन है 'ca' पता 27731511, और स्ट्रिंग पर 't'। यह concatenation पहले कैश स्ट्रिंग से मेल खाता है 'cat'। पाइथन स्वचालित रूप से इस मामले का पता नहीं लगाता है। जैसा कि दयालु संकेत दिया गया है, आप खोज को मजबूर कर सकते हैं intern() तरीका।

उम्मीद है कि यह स्पष्टीकरण उन चरणों को प्रकाशित करता है जिनके पते का पता चलता है a बदला हुआ।

आपके कोड में मध्यवर्ती राज्य शामिल नहीं था a स्ट्रिंग सौंपा गया 'ca'। उत्तर अभी भी लागू होता है, क्योंकि पाइथन दुभाषिया मध्यवर्ती परिणाम को पकड़ने के लिए एक नई स्ट्रिंग ऑब्जेक्ट उत्पन्न करता है a[0:2], चाहे आप उस इंटरमीडिएट परिणाम को एक चर या असाइन करें।


1
2017-08-04 18:24