python - हरण - पूर्णांक संख्या क्या होती है




'है' ऑपरेटर गैर-कैश्ड पूर्णांक के साथ अनपेक्षित रूप से व्यवहार करता है (2)

tl; डॉ:

संदर्भ पुस्तिका के अनुसार:

एक ब्लॉक पायथन प्रोग्राम टेक्स्ट का एक टुकड़ा है जिसे एक इकाई के रूप में निष्पादित किया जाता है। निम्नलिखित ब्लॉक हैं: एक मॉड्यूल, एक फ़ंक्शन बॉडी, और एक क्लास परिभाषा। अंतःक्रियात्मक रूप से टाइप किया गया प्रत्येक कमांड एक ब्लॉक है।

यही कारण है कि, फ़ंक्शन के मामले में, आपके पास एक एकल कोड ब्लॉक होता है जिसमें संख्यात्मक शाब्दिक 1000 लिए एक एकल ऑब्जेक्ट होता है, इसलिए id(a) == id(b) True उत्पादन करेगा।

दूसरे मामले में, आपके पास शाब्दिक 1000 id(a) != id(b) लिए अपनी अलग वस्तु के साथ दो अलग कोड ऑब्जेक्ट हैं।

ध्यान दें कि यह व्यवहार केवल इंटल लिपि के साथ प्रकट नहीं होता है, आपको इसी तरह के परिणाम प्राप्त होंगे, उदाहरण के लिए, float शाब्दिक ( here देखें)।

बेशक, वस्तुओं की तुलना करना (स्पष्ट is None छोड़कर परीक्षण is None ) हमेशा समानता ऑपरेटर == साथ किया जाना चाहिए और नहीं is

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

दीर्घ उत्तर:

थोड़ा स्पष्ट दृश्य प्राप्त करने और अतिरिक्त रूप से इस अजीब व्यवहार को सत्यापित करने के लिए, हम इन मॉड्यूल में से प्रत्येक के लिए code ऑब्जेक्ट में सीधे देख सकते हैं।

func :

अन्य सभी विशेषताओं के साथ, फ़ंक्शन ऑब्जेक्ट में एक __code__ विशेषता भी होती है जो आपको उस फ़ंक्शन के लिए संकलित __code__ अनुमति देती है। dis.code_info का उपयोग dis.code_info हम किसी दिए गए फ़ंक्शन के लिए कोड ऑब्जेक्ट में सभी संग्रहीत विशेषताओं का एक अच्छा सुंदर दृश्य प्राप्त कर सकते हैं:

>>> print(dis.code_info(func))
Name:              func
Filename:          <stdin>
Argument count:    0
Kw-only arguments: 0
Number of locals:  2
Stack size:        2
Flags:             OPTIMIZED, NEWLOCALS, NOFREE
Constants:
   0: None
   1: 1000
Variable names:
   0: a
   1: b

हम केवल फ़ंक्शन फ़ंक्शंस के लिए Constants प्रविष्टि में रुचि रखते हैं। इसमें, हम देख सकते हैं कि हमारे पास दो मूल्य हैं, None (हमेशा मौजूद) और 1000 । हमारे पास केवल एक ही अंतर है जो निरंतर 1000 प्रतिनिधित्व करता है। यह वह मान है जिसे फ़ंक्शन के आह्वान पर a और b को असाइन किया जाना है।

इस मान तक पहुँचना func.__code__.co_consts[1] माध्यम से आसान है func.__code__.co_consts[1] और, हमारे देखने का एक और तरीका a is b है कि फ़ंक्शन में a is b मूल्यांकन इस प्रकार होगा:

>>> id(func.__code__.co_consts[1]) == id(func.__code__.co_consts[1]) 

जो, निश्चित रूप से, True मूल्यांकन करेगा क्योंकि हम उसी वस्तु का उल्लेख कर रहे हैं।

प्रत्येक इंटरैक्टिव कमांड के लिए:

जैसा कि पहले उल्लेख किया गया है, प्रत्येक इंटरैक्टिव कमांड को एक ही कोड ब्लॉक के रूप में व्याख्या की जाती है: स्वतंत्र रूप से पार्स, संकलित और मूल्यांकन किया गया।

हम compile अंतर्निहित के माध्यम से प्रत्येक कमांड के लिए कोड ऑब्जेक्ट प्राप्त कर सकते हैं:

>>> com1 = compile("a=1000", filename="", mode="single")
>>> com2 = compile("b=1000", filename="", mode="single")

प्रत्येक असाइनमेंट स्टेटमेंट के लिए, हमें एक समान लुकिंग कोड ऑब्जेक्ट मिलेगा जो निम्न की तरह दिखता है:

>>> print(dis.code_info(com1))
Name:              <module>
Filename:          
Argument count:    0
Kw-only arguments: 0
Number of locals:  0
Stack size:        1
Flags:             NOFREE
Constants:
   0: 1000
   1: None
Names:
   0: a

com2 लिए समान कमांड समान दिखता है, लेकिन इसमें मूलभूत अंतर है : प्रत्येक कोड ऑब्जेक्ट com1 और com2 में शाब्दिक 1000 प्रतिनिधित्व करने वाले विभिन्न अंतर हैं। यही कारण है कि, इस मामले में, जब हम co_consts तर्क के माध्यम से a is b co_consts है, तो हम वास्तव में प्राप्त करते हैं:

>>> id(com1.co_consts[0]) == id(com2.co_consts[0])
False

जो वास्तव में हमें मिला है, उससे सहमत है।

विभिन्न कोड ऑब्जेक्ट, विभिन्न सामग्री।

नोट: मैं कुछ हद तक उत्सुक था कि स्रोत कोड में यह वास्तव में कैसे होता है और इसके माध्यम से खुदाई करने के बाद मुझे विश्वास है कि मुझे आखिरकार मिल गया।

संकलन के चरण के दौरान co_consts विशेषता को एक शब्दकोश वस्तु द्वारा दर्शाया गया है। compile.c हम वास्तव में आरंभीकरण देख सकते हैं:

/* snippet for brevity */

u->u_lineno = 0;
u->u_col_offset = 0;
u->u_lineno_set = 0;
u->u_consts = PyDict_New();  

/* snippet for brevity */

संकलन के दौरान यह पहले से मौजूद स्थिरांक के लिए जाँच की जाती है। इस पर थोड़ा और अधिक के लिए @ रेमंड हेटिंगर का जवाब नीचे देखें।

चेतावनियां:

  • जंजीर स्टेटमेंट True की एक पहचान की जाँच करने के लिए मूल्यांकन करेगा

    यह अब और अधिक स्पष्ट होना चाहिए कि वास्तव में निम्न True मूल्यांकन क्यों करते हैं:

    >>> a = 1000; b = 1000;
    >>> a is b

    इस मामले में, दो असाइनमेंट कमांड्स को एक साथ जोड़कर हम दुभाषिया को एक साथ संकलन करने के लिए कहते हैं । जैसा कि फ़ंक्शन ऑब्जेक्ट के लिए होता है, शाब्दिक 1000 लिए केवल एक ऑब्जेक्ट बनाया जाएगा, जिसके परिणामस्वरूप मूल्यांकन किए जाने पर एक True वैल्यू होगी।

  • मॉड्यूल स्तर पर निष्पादन फिर से True होता है:

    जैसा कि पहले उल्लेख किया गया है, संदर्भ पुस्तिका में कहा गया है कि:

    ... निम्नलिखित ब्लॉक हैं: एक मॉड्यूल ...

    इसलिए एक ही आधार लागू होता है: हमारे पास एक एकल कोड ऑब्जेक्ट (मॉड्यूल के लिए) होगा और इसलिए, प्रत्येक भिन्न शाब्दिक के लिए एकल मान संग्रहीत किए जाते हैं।

  • वही उत्परिवर्तनीय वस्तुओं के लिए लागू नहीं होता है:

    इसका मतलब है कि जब तक हम स्पष्ट रूप से एक ही उत्परिवर्तित वस्तु (उदाहरण के लिए = b = []] के साथ आरंभ नहीं करते हैं, उदाहरण के लिए वस्तुओं की पहचान कभी भी समान नहीं होगी:

    a = []; b = []
    a is b  # always returns false

    फिर, प्रलेखन में , यह निर्दिष्ट किया गया है:

    एक = 1 के बाद; कार्यान्वयन के आधार पर मूल्य 1 के साथ b = 1, a और b समान वस्तु को संदर्भित कर सकते हैं या नहीं भी कर सकते हैं, लेकिन c = [] के बाद; d = [], c और d दो अलग, अद्वितीय, नव निर्मित खाली सूचियों को संदर्भित करने की गारंटी है।

पायथन दुभाषिया के साथ खेलने के दौरान, मैं ऑपरेटर के बारे में इस परस्पर विरोधी मामले पर ठोकर खाई:

यदि मूल्यांकन फ़ंक्शन में होता है तो यह True , अगर यह बाहर किया जाता है तो यह False रिटर्न देता है।

>>> def func():
...     a = 1000
...     b = 1000
...     return a is b
...
>>> a = 1000
>>> b = 1000
>>> a is b, func()
(False, True)

चूंकि ऑपरेटर शामिल वस्तुओं के लिए id() मूल्यांकन करता है, इसका मतलब यह है कि a और b a ही अंतर उदाहरण के लिए इंगित करते हैं जब फ़ंक्शन फ़ंक्शंस के अंदर घोषित किया जाता है लेकिन, इसके विपरीत, वे इसके बाहर होने पर एक अलग ऑब्जेक्ट को इंगित करते हैं ।

ऐसा क्यों है?

नोट : मैं पहचान के बीच के अंतर (और) और समानता ( == ) के संचालन के बारे में जानता हूं जैसा कि अंडरस्टैंडिंग पायथन के "ऑपरेटर" में वर्णित है। इसके अलावा, मैं कैशिंग के बारे में भी जानता हूं जो कि पूर्णांक के लिए अजगर द्वारा रेंज [-5, 256] में किया जा रहा है जैसा कि "" में वर्णित है "ऑपरेटर पूर्णांक के साथ अप्रत्याशित व्यवहार करता है

यहाँ ऐसा नहीं है क्योंकि संख्याएँ उस सीमा के बाहर हैं और मैं पहचान का मूल्यांकन करना चाहता हूँ न कि समानता का।


इंटरेक्टिव प्रॉम्प्ट में, प्रविष्टि को एक एकल मोड में संकलित किया जाता है जो एक समय में एक पूर्ण विवरण को संसाधित करता है। कंपाइलर ही ( Python/compile.c ) स्थिरांक को u_consts नामक डिक्शनरी में ट्रैक करता है जो निरंतर ऑब्जेक्ट को उसके इंडेक्स पर मैप करता है।

compiler_add_o() फ़ंक्शन में, आप देखते हैं कि एक नया स्थिरांक जोड़ने से पहले (और अनुक्रमणिका में वृद्धि), यह देखने के लिए कि क्या निरंतर वस्तु और सूचकांक पहले से मौजूद हैं, तानाशाही की जाँच की जाती है। यदि हां, तो उनका पुन: उपयोग किया जाता है।

संक्षेप में, इसका मतलब है कि एक बयान (जैसे कि आपके फ़ंक्शन की परिभाषा में) में दोहराया स्थिरांक एक सिंगलटन में बदल जाते हैं। इसके विपरीत, आपका a = 1000 और b = 1000 दो अलग-अलग कथन हैं, इसलिए कोई तह नहीं होती है।

FWIW, यह सब सिर्फ एक CPython कार्यान्वयन विवरण है (अर्थात भाषा द्वारा इसकी गारंटी नहीं)। यही कारण है कि यहां दिए गए संदर्भ भाषा विनिर्देश के बजाय सी स्रोत कोड के हैं जो विषय पर कोई गारंटी नहीं देता है।

आशा है कि आपको यह जानकारी अच्छी लगी होगी कि सीपीथॉन कैसे हुड के तहत काम करता है :-)







python-internals