पायथन स्ट्रिंग इंटर्निंग


92

हालांकि इस प्रश्न का व्यवहार में कोई वास्तविक उपयोग नहीं है, लेकिन मैं उत्सुक हूं कि पायथन स्ट्रिंग इंटर्निंग कैसे करता है। मैंने निम्नलिखित पर ध्यान दिया है।

>>> "string" is "string"
True

यह मेरी अपेक्षा के अनुसार है।

आप यह भी कर सकते हैं।

>>> "strin"+"g" is "string"
True

और यह बहुत चालाक है!

लेकिन आप ऐसा नहीं कर सकते।

>>> s1 = "strin"
>>> s2 = "string"
>>> s1+"g" is s2
False

पायथन का मूल्यांकन क्यों नहीं होगा s1+"g", और यह महसूस होगा कि यह समान है s2और इसे उसी पते पर इंगित करता है? वास्तव में उस आखिरी ब्लॉक में क्या हो रहा है कि उसे वापस करना है False?

जवाबों:


95

यह कार्यान्वयन-विशिष्ट है, लेकिन आपका दुभाषिया संभवतः संकलन-समय स्थिरांक को नजरअंदाज कर रहा है, लेकिन रन-टाइम अभिव्यक्तियों के परिणाम नहीं हैं।

मैं किस तरह से सीपीथॉन 2.7.3 का उपयोग करता हूं।

दूसरे उदाहरण में, "strin"+"g"संकलित समय पर अभिव्यक्ति का मूल्यांकन किया जाता है, और इसके साथ प्रतिस्थापित किया जाता है "string"। यह पहले दो उदाहरणों के समान व्यवहार करता है।

यदि हम bytecodes की जांच करते हैं, तो हम देखेंगे कि वे बिल्कुल समान हैं:

  # s1 = "string"
  2           0 LOAD_CONST               1 ('string')
              3 STORE_FAST               0 (s1)

  # s2 = "strin" + "g"
  3           6 LOAD_CONST               4 ('string')
              9 STORE_FAST               1 (s2)

तीसरे उदाहरण में एक रन-टाइम कॉन्टेनेशन शामिल है, जिसके परिणाम को स्वचालित रूप से नजरबंद नहीं किया गया है:

  # s3a = "strin"
  # s3 = s3a + "g"
  4          12 LOAD_CONST               2 ('strin')
             15 STORE_FAST               2 (s3a)

  5          18 LOAD_FAST                2 (s3a)
             21 LOAD_CONST               3 ('g')
             24 BINARY_ADD          
             25 STORE_FAST               3 (s3)
             28 LOAD_CONST               0 (None)
             31 RETURN_VALUE        

यदि आप intern()तीसरी अभिव्यक्ति के परिणाम को मैन्युअल रूप से लेते हैं, तो आपको पहले जैसी ही वस्तु मिलेगी:

>>> s3a = "strin"
>>> s3 = s3a + "g"
>>> s3 is "string"
False
>>> intern(s3) is "string"
True

22
और रिकॉर्ड के लिए: संकलन के समय (या "string1" + "s2", 10 + 3*20आदि) पर पायथन के पीप-होल ऑप्टिमाइज़ेशन अंकगणितीय ऑपरेशनों की पूर्व-गणना करेगा , लेकिन परिणामी अनुक्रमों को केवल 20 तत्वों तक सीमित करता है ( [None] * 10**1000अपने बायोटेक का विस्तार करने से रोकने के लिए )। यह वह अनुकूलन है जो ढह "strin" + "g"गया "string"; परिणाम 20 वर्णों से छोटा है।
मार्टिज़न पीटरर्स

13
और यह स्पष्ट रूप से स्पष्ट करने के लिए: यहां बिल्कुल भी इंटर्न नहीं चल रहा है। अपरिवर्तनीय शाब्दिक बाइटेकोड के साथ स्थिरांक के रूप में संग्रहीत किए जाते हैं। कोडिंग में उपयोग किए जाने वाले नामों के लिए इंटरस्टिंग होता है , लेकिन प्रोग्राम द्वारा बनाए गए स्ट्रिंग मानों के लिए नहीं जब तक कि intern()फ़ंक्शन द्वारा विशेष रूप से इंटर्न नहीं किया जाता है।
मार्टिन पीटर्स

9
उन, जो खोजने की कोशिश करता लिए internअजगर 3 में समारोह - यह करने के लिए ले जाया जाता है sys.intern
Timofey Chernousov

1

मामला एक

>>> x = "123"  
>>> y = "123"  
>>> x == y  
True  
>>> x is y  
True  
>>> id(x)  
50986112  
>>> id(y)  
50986112  

केस 2

>>> x = "12"
>>> y = "123"
>>> x = x + "3"
>>> x is y
False
>>> x == y
True

अब, अपने प्रश्न क्यों आईडी मामले 1 में एक ही है और मामले 2 में नहीं है
मामला 1 में, आप शाब्दिक एक स्ट्रिंग सौंपा है "123"करने के लिए xऔर y

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

मामले 2 में, आप संघनन xका उपयोग करके संशोधन कर रहे हैं । दोनों xऔर yएक ही मान, लेकिन एक ही पहचान है।
दोनों स्मृति में विभिन्न वस्तुओं की ओर इशारा करते हैं। इसलिए वे अलग हैं idऔर isऑपरेटर लौट आएFalse


कैसे आते हैं, क्योंकि तार अपरिवर्तनीय हैं, x + "3" असाइन करना (और स्ट्रिंग को स्टोर करने के लिए एक नए स्थान की तलाश करना) y के समान संदर्भ में निर्दिष्ट नहीं करता है?
21

क्योंकि तब इसे सभी मौजूदा तारों के साथ नए स्ट्रिंग की तुलना करने की आवश्यकता होती है; संभावित रूप से एक बहुत महंगा ऑपरेशन। यह ऐसा हो सकता है कि मैं काम करने के बाद पृष्ठभूमि में, स्मृति को कम करने के लिए, लेकिन तब आप भी अजनबी व्यवहार के साथ समाप्त हो जाएगा: id(x) != id(x)उदाहरण के लिए, क्योंकि स्ट्रिंग मूल्यांकन की प्रक्रिया में ले जाया गया था।
डायलनयुंग

1
@AndreaConte क्योंकि स्ट्रिंग्स का कॉन्सेप्टेशन हर बार इस्तेमाल किए गए स्ट्रिंग्स के पूल में देखने का अतिरिक्त काम नहीं करता है, क्योंकि यह एक नया उत्पन्न करता है। दूसरी ओर, दुभाषिया अभिव्यक्ति x = "12" + "3"को "एक अभिव्यक्ति में x = "123"दो स्ट्रिंग शाब्दिकों का मिलन " के रूप में "अनुकूलित करता है" इसलिए असाइनमेंट वास्तव में लुकअप करता है और इसके लिए उसी "आंतरिक" स्ट्रिंग को ढूंढता है y = "123"
derenio

वास्तव में, ऐसा नहीं है कि स्रोत कोड से प्रत्येक स्ट्रिंग शाब्दिक के बजाय लुकअप करता है "आंतरिक" हो जाता है और अन्य सभी स्थानों में उस ऑब्जेक्ट का पुन: उपयोग होता है।
derenio
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.