क्या अजगर चर बिंदु हैं? वरना वे क्या हैं?


82

पाइथन में चर सिर्फ संकेत हैं, जहां तक ​​मुझे पता है।

इस नियम के आधार पर, मैं मान सकता हूं कि इस कोड के लिए परिणाम स्निपेट:

i = 5
j = i
j = 3 
print(i)

होगा 3। लेकिन मुझे मेरे लिए एक अप्रत्याशित परिणाम मिला, यह था 5

इसके अलावा, मेरी पायथन पुस्तक इस उदाहरण को कवर करती है:

i = [1,2,3]
j = i
i[0] = 5
print(j)

परिणाम होगा [5,2,3]

मैं क्या गलत समझ रहा हूँ?



5
मैं नहीं देखता कि कैसे iहोना चाहिए3
टोनीसिस

@Tooniis j अब मेमोरी के एक अलग ब्लॉक की ओर इशारा करता है, जो कि मैं इशारा कर रहा हूं, के अलावा। आप शायद अब तक समझ गए हैं, लेकिन बस किसी और को यह देखने पर
स्वरूप जोशी

जवाबों:


89

हम उन्हें संदर्भ कहते हैं। वे इस तरह काम करते हैं

i = 5     # create int(5) instance, bind it to i
j = i     # bind j to the same int as i
j = 3     # create int(3) instance, bind it to j
print i   # i still bound to the int(5), j bound to the int(3)

छोटे चींटियों को नजरबंद कर दिया जाता है, लेकिन यह इस स्पष्टीकरण के लिए महत्वपूर्ण नहीं है

i = [1,2,3]   # create the list instance, and bind it to i
j = i         # bind j to the same list as i
i[0] = 5      # change the first item of i
print j       # j is still bound to the same list as i

3
हाय जॉन, 'छोटे ints नजरबंद हैं' से आपका क्या तात्पर्य है? धन्यवाद!
युअकली

6
@#qli अजगर में, सब कुछ एक वस्तु है, जिसमें संख्याएं भी शामिल हैं। चूंकि छोटी संख्या (-5,256) का उपयोग किया जाता है, वे अक्सर "इंटर्न" या सीपीथॉन में कैश्ड होते हैं। इस प्रकार, हर बार जब आप टाइप 40करते हैं, तो आप उसी ऑब्जेक्ट को मेमोरी में संदर्भित कर रहे हैं। इस प्रकार को देखने के लिए, बी = 256 और परीक्षण करें a is b। अब इसे a, b = 257 के साथ आज़माएँ। देखें: stackoverflow.com/a/1136852/3973834 और codementor.io/python/tutorial/…
इवान रोजिका

3
मेरे अनुभव में, उन्हें "नाम" कहना पायथन डेवलपर्स के बीच अधिक सामान्य है। शब्द "संदर्भ" अनावश्यक सी सामान के साथ आता है, और शायद पायथन ( भाषा ) को बहुत अधिक CPython ( कार्यान्वयन ) की ओर ले जाता है, जो संदर्भ गिनती का उपयोग करने के लिए होता है।
विम

33

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

आपके पहले उदाहरण में नाम iमान के लिए बाध्य है 5। नाम पर अलग-अलग मानों को बांधने jका कोई प्रभाव नहीं पड़ता है i, इसलिए जब आप बाद में मूल्य का प्रिंट लेते हैं तब iभी मूल्य होता है 5

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

ध्यान दें कि यदि आपने "दोनों सूचियाँ बदल दी हैं" तो यह गलत होगा। केवल एक सूची है लेकिन इसके दो नाम ( iऔर j) हैं जो इसे संदर्भित करते हैं।

संबंधित दस्तावेज


15

अजगर चर वस्तुओं के लिए बाध्य नाम हैं

से डॉक्स :

नामों से तात्पर्य वस्तुओं से है। नाम बाइंडिंग ऑपरेशन द्वारा नाम पेश किए जाते हैं। कार्यक्रम पाठ में एक नाम की प्रत्येक घटना का उपयोग करने के लिए अंतरतम फ़ंक्शन ब्लॉक में स्थापित उस नाम के बंधन को संदर्भित करता है

जब तुम करोगे

i = 5
j = i

यह ऐसा ही है:

i = 5
j = 5

jiअसाइनमेंट के बाद और उसके बाद इंगित नहीं करता है , jयह नहीं पता है कि iमौजूद है। jबस iअसाइनमेंट के समय जो कुछ भी इंगित कर रहा था, उसके लिए बाध्य है ।

यदि आपने एक ही पंक्ति में असाइनमेंट किए हैं, तो यह इस तरह दिखेगा:

i = j = 5

और नतीजा बिल्कुल वही होगा।

इस प्रकार, बाद में कर रहे हैं

i = 3

j- जो इंगित कर रहा है वह नहीं बदलता है - और आप इसे स्वैप कर सकते हैं - j = 3जो iइंगित कर रहा है वह नहीं बदलेगा ।

आपका उदाहरण सूची के संदर्भ को नहीं हटाता है

तो जब आप ऐसा करते हैं:

i = [1,2,3]
j = i

यह ऐसा ही कर रहा है:

i = j = [1,2,3]

इसलिए iऔर jदोनों एक ही सूची में इंगित करते हैं। तब आपका उदाहरण सूची को बदल देता है:

i[0] = 5

पाइथन लिस्ट परस्पर वस्तुएँ हैं, इसलिए जब आप सूची को एक संदर्भ से बदलते हैं, और आप इसे दूसरे संदर्भ से देखते हैं, तो आपको वही परिणाम दिखाई देगा क्योंकि यह समान सूची है।


9

TLDR: पायथन नाम स्वचालित डी / संदर्भित के साथ संकेत की तरह काम करते हैं लेकिन स्पष्ट सूचक संचालन की अनुमति नहीं देते हैं। अन्य लक्ष्य अप्रत्यक्षों का प्रतिनिधित्व करते हैं, जो संकेत के समान व्यवहार करते हैं।


सीपीथॉन कार्यान्वयन हुड के तहत प्रकारPyObject* के पॉइंटर्स का उपयोग करता है । जैसे, नाम से शब्दार्थों को सूचक कार्यों में अनुवाद करना संभव है। कुंजी वास्तविक वस्तुओं से नामों को अलग करने के लिए है ।

उदाहरण पायथन कोड में नाम ( i) और ऑब्जेक्ट्स ( 5) दोनों शामिल हैं ।

i = 5  # name `i` refers to object `5`
j = i  # ???
j = 3  # name `j` refers to object `3`

इसे अलग-अलग नामों और वस्तुओं के साथ मोटे तौर पर सी कोड में अनुवाद किया जा सकता है ।

int three=3, five=5;  // objects
int *i, *j;           // names
i = &five;   // name `i` refers to position of object `5`
j = i;       // name `j` refers to referent of `i`
j = &three;  // name `j` refers to position of object `3`

महत्वपूर्ण हिस्सा यह है कि "नाम-के-संकेत" वस्तुओं को संग्रहीत नहीं करते हैं! हमने परिभाषित नहीं किया *i = five, लेकिन i = &five। नाम और वस्तु एक दूसरे से स्वतंत्र होते हैं।

नाम केवल मौजूदा वस्तुओं को स्मृति में इंगित करते हैं

नाम से नाम निर्दिष्ट करते समय, कोई भी वस्तुओं का आदान-प्रदान नहीं किया जाता है! जब हम परिभाषित करते हैं j = i, तो यह बराबर होता है j = &five। न तो iहै और न ही jदूसरे से जुड़े हैं।

+- name i -+ -\
               \
                --> + <five> -+
               /    |        5 |
+- name j -+ -/     +----------+

परिणामस्वरूप, एक नाम के लक्ष्य को बदलने से दूसरे पर कोई असर नहीं पड़ता है । यह केवल वही अपडेट करता है जो उस विशिष्ट नाम को इंगित करता है।


पायथन में अन्य प्रकार के नाम जैसे तत्व भी हैं : विशेषता संदर्भ ( i.j), सदस्यता ( i[j]) और टुकड़ा करने की क्रिया ( i[:j])। नामों के विपरीत, जो वस्तुओं को सीधे संदर्भित करते हैं, तीनों अप्रत्यक्ष रूप से वस्तुओं के तत्वों को संदर्भित करते हैं।

उदाहरण कोड में दोनों नाम ( i) और एक सदस्यता ( i[0]) शामिल हैं।

i = [1,2,3]  # name `i` refers to object `[1, 2, 3]`
j = i        # name `j` refers to referent of `i`
i[0] = 5     # ???

एक सीपीथॉन हुड के नीचे बिंदुओं की listएक सी सरणी का उपयोग करता है PyObject*। इसे फिर से अलग-अलग नामों और वस्तुओं के साथ सी कोड में अनुवाद किया जा सकता है।

typedef struct{
    int *elements[3];
} list;  // length 3 `list` type

int one = 1, two = 2, three = 3, five = 5;
list values = {&one, &two, &three};  // objects
list *i, *j;                         // names
i = &values;             // name `i` refers to object `[1, 2, 3]`
j = i;                   // name `j` refers to referent of `i`
i->elements[0] = &five;  // leading element of `i` refers to object `5`

महत्वपूर्ण बात यह है कि हमने कोई भी नाम नहीं बदला है! हमने परिवर्तन किया i->elements[0], एक वस्तु का तत्व जो हमारे नाम दोनों को इंगित करता है।

मौजूदा यौगिक वस्तुओं के मूल्यों को बदला जा सकता है।

नाम के माध्यम से किसी वस्तु के मूल्य को बदलते समय , नाम नहीं बदले जाते हैं। दोनों iऔर jअभी भी उसी वस्तु को संदर्भित करते हैं, जिसका मूल्य हम बदल सकते हैं।

+- name i -+ -\
               \
                --> + <values> -+
               /    |  elements | --> [1, 2, 3]
+- name j -+ -/     +-----------+

मध्यवर्ती वस्तु एक पॉइंटर के समान व्यवहार करती है जिसमें हम सीधे उसको बदल सकते हैं जो इसे इंगित करता है और इसे कई नामों से संदर्भित करता है।


1
मुझे वास्तव में यह उत्तर पसंद है, लेकिन मुझे लगता है कि आपने अपने उदाहरण में उलटा iऔर jअसाइनमेंट किया है। आप के साथ शुरू करते हैं i = 5, j = 3और फिर उन्हें अपने पोस्ट के बाकी हिस्सों में उल्टा करते हैं। उस ने फिर कहा, यह एकमात्र उत्तर है जो ओपी में सवाल के साथ न्याय करता है और वास्तव में समझाता है कि हुड के तहत क्या होता है।
जेरेमी रेडक्लिफ

1
@jeremyradcliff सिर के लिए धन्यवाद। अब तय होना चाहिए। मुझे पता है अगर मैं कुछ और याद किया।
मिस्टरमियागी

7

वे काफी संकेत नहीं हैं, वे वस्तुओं के संदर्भ हैं। ऑब्जेक्ट या तो उत्परिवर्तनीय या अपरिवर्तनीय हो सकते हैं। संशोधित होने पर एक अपरिवर्तनीय वस्तु की नकल की जाती है। एक परिवर्तनशील वस्तु को जगह में बदल दिया जाता है। पूर्णांक एक अपरिवर्तनीय वस्तु है, जिसे आप अपने i और j चर द्वारा संदर्भित करते हैं। एक सूची एक परिवर्तनशील वस्तु है।

अपने पहले उदाहरण में

i=5
# The label i now references 5
j=i
# The label j now references what i references
j=3
# The label j now references 3
print i
# i still references 5

अपने दूसरे उदाहरण में:

i=[1,2,3]
# i references a list object (a mutable object)
j=i
# j now references the same object as i (they reference the same mutable object)
i[0]=5
# sets first element of references object to 5
print j
# prints the list object that j references. It's the same one as i.

"जब इसे संशोधित किया जाता है तो एक अपरिवर्तनीय वस्तु की नकल की जाती है।" यह थोड़ा आत्म-विरोधाभासी है।
PM 2Ring

1

जब आप सेट j=3करते हैं तो लेबल jलागू नहीं होता है (अंक) i, यह पूर्णांक को इंगित करता है 3। नाम iअभी भी, आप मूल रूप से सेट मूल्य के लिए बात कर रहा है 5


1

'=' चिह्न के बाईं ओर जो भी चर है, उसे '=' के दाईं ओर के मान के साथ असाइन किया गया है

i = 5

j = i --- j में 5 हैं

j = 3 --- j में 3 है (5 के मान को ओवरराइट करता है) लेकिन i के संबंध में कुछ भी नहीं बदला गया है

print(i)- तो यह 5 प्रिंट


1

असाइनमेंट वस्तुओं को संशोधित नहीं करता है; यह सब करता है परिवर्तन जहां चर अंक। जहां परिवर्तन एक चर अंक जहां एक और एक अंक नहीं बदलेगा।

आप शायद इस तथ्य के बारे में सोच रहे हैं कि सूचियाँ और शब्दकोश परस्पर प्रकार हैं। वास्तविक ऑब्जेक्ट को इन-प्लेस में संशोधित करने के लिए ऑपरेटर हैं, और यदि आप उनमें से किसी एक का उपयोग करते हैं, तो आप एक ही वस्तु की ओर इशारा करते हुए सभी चर में परिवर्तन देखेंगे:

x = []
y = x
x.append(1)
# x and y both are now [1]

लेकिन असाइनमेंट अभी भी सूचक को चारों ओर ले जाता है:

x = [2]
# x now points to new list [2]; y still points to old list [1]

संख्याएँ, शब्दकोशों और सूचियों के विपरीत, अपरिवर्तनीय हैं। यदि आप करते हैं x = 3; x += 2, तो आप नंबर 3 को नंबर 5 में नहीं बदल रहे हैं; आप सिर्फ x5 के बजाय परिवर्तनशील बिंदु बना रहे हैं । 3 अभी भी अपरिवर्तित है, और इसे इंगित करने वाले कोई भी चर अभी भी 3 को उनके मूल्य के रूप में देखेंगे।

(वास्तविक कार्यान्वयन में, संख्याएं संभवतः संदर्भ प्रकार नहीं हैं; यह अधिक संभावना है कि चर वास्तव में इंगित करने के बजाय सीधे मूल्य का प्रतिनिधित्व करते हैं। लेकिन उस कार्यान्वयन विस्तार से शब्दार्थ नहीं बदलता है जहां अपरिवर्तनीय प्रकार चिंतित हैं। ।)


1
यही कारण है कि मूल्य प्रकार का मतलब नहीं है। मूल्य प्रकार साधन ठीक क्या आप पिछले पैरा में वर्णित (कि मूल्य पारित हो जाता है / वस्तु के लिए एक संदर्भ के बजाय भर में इसकी नक़ल), और यह है नहीं (आंतरिक ऐसा CPython में, और PyPy बिना JIT कम्पाइलर में - हर पूर्णांक एक है ढेर-आवंटित वस्तु)। बस अपरिवर्तनीय रहें, ठीक वही शब्द है जिसकी आपको आवश्यकता है।

-1

पायथन में, सब कुछ ऑब्जेक्ट है जिसमें मेमोरी के टुकड़े शामिल होते हैं जो आपको वापस कर दिए जाते हैं। इसका मतलब है, जब नई मेमोरी चंक बनाई जाती है (चाहे आपने जो भी बनाया हो: इंट, स्ट्र, कस्टम ऑब्जेक्ट आदि), आपके पास एक नई मेमोरी ऑब्जेक्ट है। आपके मामले में यह 3 का असाइनमेंट है जो एक नई (मेमोरी) ऑब्जेक्ट बनाता है और इस तरह एक नया पता होता है।

यदि आप निम्नलिखित चलाते हैं, तो आप देखते हैं कि मेरा क्या मतलब है।

i = 5
j = i
print("id of j: {}", id(j))
j = 3
print("id of j: {}", id(j))

IMO, मेमोरी वार, यह C और पायथन के बीच की महत्वपूर्ण समझ / अंतर है। C / C ++ में, आपको एक मेमोरी ऑब्जेक्ट के बजाय एक मेमोरी पॉइंटर (यदि आप पॉइंटर सिंटैक्स का उपयोग करते हैं) लौटाया जाता है जो आपको संदर्भित पते को बदलने के संदर्भ में अधिक लचीलापन देता है।

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