अजगर एक ही मूल्य के कई चर असाइन कर रहा है? सूची व्यवहार


131

मैंने वेरिएबल्स को इनिशियलाइज़ करने के लिए नीचे दिए गए शो के रूप में कई असाइनमेंट का उपयोग करने की कोशिश की, लेकिन मैं व्यवहार से भ्रमित हो गया, मैं अलग से मान सूची को फिर से असाइन करने की उम्मीद करता हूं, मेरा मतलब है कि बी [0] और सी [0] बराबर 0 पहले की तरह।

a=b=c=[0,3,5]
a[0]=1
print(a)
print(b)
print(c)

परिणाम है: [1, 3, 5] [1, 3, 5] [1, 3, 5]

क्या वो सही है? मुझे कई असाइनमेंट के लिए क्या उपयोग करना चाहिए? इससे अलग क्या है?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

परिणाम: ('f:', 3) ('e:', 4)


2
क्या आप चाहते हैं a, bऔर, c,एक ही मूल्य के लिए सभी बिंदु (इस मामले में एक सूची) के लिए, या आप चाहते हैं a=0, b=3और, c=5। उस मामले में, आप चाहते हैं a,b,c = [0,3,5]या बस a,b,c = 0,3,5
चेपनर

जवाबों:


271

यदि आप C / Java / etc की भाषा से पायथन में आ रहे हैं। परिवार, यह आपको a"चर" के रूप में सोचने से रोकने में मदद कर सकता है , और इसे "नाम" के रूप में सोचना शुरू कर सकता है।

a, bऔर cसमान मूल्यों वाले विभिन्न चर नहीं हैं; वे समान समान मूल्य के लिए अलग-अलग नाम हैं। चर के प्रकार, पहचान, पते और सभी प्रकार के सामान हैं।

नामों में से कोई भी नहीं है। मूल्य , निश्चित रूप से, और आपके पास समान मूल्य के लिए बहुत सारे नाम हो सकते हैं।

यदि आप Notorious B.I.G.एक हॉट डॉग देते हैं, * Biggie Smallsऔर Chris Wallaceएक हॉट डॉग है। यदि आप a1 के पहले तत्व को बदलते हैं , तो 1 के पहले तत्व हैं bऔर c1 हैं।

यदि आप जानना चाहते हैं कि क्या दो नाम एक ही वस्तु का नाम दे रहे हैं, तो isऑपरेटर का उपयोग करें :

>>> a=b=c=[0,3,5]
>>> a is b
True

आप तब पूछते हैं:

इससे अलग क्या है?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

यहां, आप नाम eको मान पर रीबाइंड कर रहे हैं 4। यह नामों dऔर fकिसी भी तरह से प्रभावित नहीं करता है ।

अपने पिछले संस्करण में, आप को निर्दिष्ट कर रहे थे a[0], को नहीं a। इसलिए, a[0]आप के दृष्टिकोण से , आप विद्रोह कर रहे हैं a[0], लेकिन देखने के बिंदु से a, आप इसे जगह में बदल रहे हैं।

आप idफ़ंक्शन का उपयोग कर सकते हैं , जो आपको ऑब्जेक्ट की पहचान का प्रतिनिधित्व करने वाले कुछ अद्वितीय नंबर देता है, यह देखने के लिए कि वास्तव में कौन सी वस्तु है जो तब भी isमदद नहीं कर सकती है:

>>> a=b=c=[0,3,5]
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261120
>>> id(b[0])
4297261120

>>> a[0] = 1
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261216
>>> id(b[0])
4297261216

सूचना जो a[0]4297261120 से बदलकर 4297261216 हो गई है - अब यह एक अलग मूल्य के लिए एक नाम है। और b[0]अब उसी नए मूल्य के लिए एक नाम भी है। ऐसा इसलिए है क्योंकि aऔर bअभी भी एक ही वस्तु नामकरण कर रहे हैं।


कवर के तहत, a[0]=1वास्तव में सूची ऑब्जेक्ट पर एक विधि कह रहा है। (यह बराबर है a.__setitem__(0, 1)।) तो, यह वास्तव में कुछ भी नहीं विद्रोह कर रहा है। यह बुलाने जैसा है my_object.set_something(1)। निश्चित रूप से, इस विधि को लागू करने के लिए ऑब्जेक्ट एक उदाहरण विशेषता को रिबंड कर रहा है, लेकिन यह महत्वपूर्ण नहीं है; यह महत्वपूर्ण है कि आप कुछ भी निर्दिष्ट नहीं कर रहे हैं, आप केवल वस्तु को बदल रहे हैं। और इसके साथ भी ऐसा ही है a[0]=1


user570826 ने पूछा:

अगर हमारे पास है, a = b = c = 10

ठीक वैसी ही स्थिति है a = b = c = [1, 2, 3]: आपके पास एक ही मूल्य के तीन नाम हैं।

लेकिन इस मामले में, मूल्य एक है int, और intएस अपरिवर्तनीय हैं। या तो मामले में, आप rebind कर सकते हैं aएक अलग मूल्य (जैसे, करने के लिए a = "Now I'm a string!"), लेकिन मूल मूल्य है, जो प्रभावित नहीं करेगा bऔर cअभी भी के लिए नाम हो जाएगा। अंतर यह है कि एक सूची के साथ, आप मूल्य बदल सकते हैं [1, 2, 3]में [1, 2, 3, 4]ऐसा करके, जैसे, a.append(4); चूँकि वह वास्तव में मूल्य बदल रहा है bऔर उसके cलिए नाम हैं, bअब b होगा [1, 2, 3, 4]। मूल्य 10को किसी और चीज़ में बदलने का कोई तरीका नहीं है। 1010 हमेशा के लिए है, जैसे क्लाउडिया वैम्पायर 5 हमेशा के लिए है (कम से कम जब तक वह क्रिस्टन डंस्ट द्वारा प्रतिस्थापित नहीं किया जाता है)।


* चेतावनी: कुख्यात बीआईजी को हॉट डॉग न दें। गैंगस्टा रैप लाश को आधी रात के बाद कभी नहीं खिलाना चाहिए।


क्या होगा अगर हम have, a = b = c = 10;और जब हम बी के मूल्य को अपडेट करने की कोशिश करते हैं, तो यह किसी अन्य पर प्रभाव डालता है? हालाँकि मैंने जाँच की कि उनकी आईडी समान हैं।
एजे

@ user570826: 10अपरिवर्तनीय है - इसका मतलब है कि मूल्य को अपडेट करने का कोई तरीका नहीं है, इसलिए आपके प्रश्न का कोई मतलब नहीं है। आप bएक अलग मूल्य पर इंगित कर सकते हैं , लेकिन ऐसा करने पर कोई प्रभाव नहीं पड़ता है aऔर c, जो अभी भी मूल मूल्य की ओर इशारा कर रहे हैं। जो अंतर सूची बनाता है, वह यह है कि वे परस्पर-जैसे हैं, आप appendकिसी सूची में जा सकते हैं , या lst[0] = 3वह मान अपडेट करेगा, जो उस मान के लिए सभी नामों के माध्यम से दिखाई देगा।
१ert

72

खांसी की स्थिति में खांसना

>>> a,b,c = (1,2,3)
>>> a
1
>>> b
2
>>> c
3
>>> a,b,c = ({'test':'a'},{'test':'b'},{'test':'c'})
>>> a
{'test': 'a'}
>>> b
{'test': 'b'}
>>> c
{'test': 'c'}
>>> 

10
IMHO, यह वास्तव में ओपी के पहले महत्वपूर्ण सवाल का जवाब देता है कि मुझे कई असाइनमेंट के लिए क्या उपयोग करना चाहिए, जबकि उच्च श्रेणी निर्धारण और अधिक सेरेब्रल उत्तर बिना उसके उत्तर नहीं देता है।
विल क्रॉफर्ड

2
या a,b,c = 1,2,3बिना ब्रैकेट पायथन 2 या 3 में काम करता है, अगर यू वास्तव में चाहते हैं कि पठनीयता का अतिरिक्त सेमी।
विल क्रॉफर्ड

14

हां, यह अपेक्षित व्यवहार है। ए, बी और सी सभी एक ही सूची के लिए लेबल के रूप में सेट किए गए हैं। यदि आप तीन अलग-अलग सूचियाँ चाहते हैं, तो आपको उन्हें अलग-अलग निर्दिष्ट करना होगा। आप या तो स्पष्ट सूची को दोहरा सकते हैं, या किसी सूची को कॉपी करने के कई तरीकों में से एक का उपयोग कर सकते हैं:

b = a[:] # this does a shallow copy, which is good enough for this case
import copy
c = copy.deepcopy(a) # this does a deep copy, which matters if the list contains mutable objects

पायथन में असाइनमेंट स्टेटमेंट ऑब्जेक्ट्स की प्रतिलिपि नहीं बनाते हैं - वे किसी ऑब्जेक्ट को नाम बांधते हैं, और एक ऑब्जेक्ट में आपके द्वारा सेट किए गए कई लेबल हो सकते हैं। अपने पहले संपादन में, [0] को बदलते हुए, आप एकल सूची के एक तत्व को अद्यतन कर रहे हैं जिसे a, b और c सभी संदर्भित करते हैं। अपने दूसरे में, ई बदलते हुए, आप ई को एक अलग वस्तु (4 के बजाय 4) के लेबल के रूप में बदल रहे हैं।


13

अजगर में, सब कुछ एक वस्तु है, "सरल" चर प्रकार (इंट, फ्लोट, आदि ..)।

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

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

अपने उदाहरण के लिए, जब आप करते हैं:

a = b =  5 

इसका अर्थ है कि a और b स्मृति में समान पते की ओर इशारा करते हैं जिसमें मान 5 होता है, लेकिन जब आप करते हैं:

a = 6

यह b को प्रभावित नहीं करता है क्योंकि यह अब एक और मेमोरी लोकेशन की ओर इशारा करता है जिसमें 6 होता है और b में अभी भी मेमोरी एड्रेस होता है जिसमें 5 होता है।

लेकिन, जब आप करते हैं:

a = b = [1,2,3]

a और b, फिर से, एक ही स्थान को इंगित करते हैं लेकिन अंतर यह है कि यदि आप सूची मानों में से एक को बदलते हैं:

a[0] = 2

यह उस मेमोरी के मान को बदलता है जो a पर इंगित करता है, लेकिन a अभी भी b के समान पते पर इंगित करता है, और इसके परिणामस्वरूप, b भी बदलता है।


6
यह बेहद भ्रामक है। पायथन स्तर पर पॉइंटर्स निश्चित रूप से दिखाई नहीं देते हैं, और चार प्रमुख कार्यान्वयन (PyPy और Jython) में से कम से कम दो कार्यान्वयन के अंदर भी उनका उपयोग नहीं करते हैं।
abarnert

1
आप अजगर इंटर्न को पढ़ने और तलाशने का स्वागत करते हैं और आपको पता चलेगा कि अजगर में हर चर वास्तव में सूचक है।
ओरी सेरी

4
नहीं। पायथन (CPython) के एक कार्यान्वयन में, प्रत्येक चर a का सूचक है PyObject। यह PyPy या Jython जैसे अन्य कार्यान्वयनों में सही नहीं है। (वास्तव में, यह भी स्पष्ट नहीं है कि यह कैसे हो सकता है सच हो, क्योंकि भाषाओं उन कार्यान्वयन में लिखा जाता है यहां तक कि संकेत नहीं है।)
abarnert

मुझे लगता है कि वैचारिक अर्थ में "पॉइंटर" का उपयोग ठीक है (शायद एक डिस्क्लेमर के साथ कि कार्यान्वयन अलग-अलग हो सकते हैं), अगर लक्ष्य व्यवहार को व्यक्त करना है।
लेवोन

@abarnert जब लोग कहते हैं कि अजगर का मतलब है कि वे सीपीथॉन हैं, तो अन्य शायद ही कभी इस्तेमाल किए गए कार्यान्वयन नहीं थे। ठीक उसी तरह जब लोग क्लेनेक्स कहते हैं कि उनका मतलब चेहरे के ऊतकों से है। इन टिप्पणियों में शब्दार्थ खेल खेलना वास्तव में अनावश्यक है। जैसा उसने लिखा, क्या उसने जो गलत बताया उसका व्यवहार क्या है?
swade

10

आप यह id(name)जांचने के लिए उपयोग कर सकते हैं कि क्या दो नाम समान वस्तु का प्रतिनिधित्व करते हैं:

>>> a = b = c = [0, 3, 5]
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488

सूचियाँ परस्पर हैं; इसका अर्थ है कि आप एक नई वस्तु बनाए बिना मूल्य बदल सकते हैं। हालाँकि, यह इस बात पर निर्भर करता है कि आप मूल्य कैसे बदलते हैं:

>>> a[0] = 1
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488
>>> print(a, b, c)
[1, 3, 5] [1, 3, 5] [1, 3, 5]

यदि आप एक नई सूची असाइन करते हैं a, तो इसकी आईडी बदल जाएगी, इसलिए यह प्रभावित नहीं करेगा bऔर इसका cमान:

>>> a = [1, 8, 5]
>>> print(id(a), id(b), id(c))
139423880 46268488 46268488
>>> print(a, b, c)
[1, 8, 5] [1, 3, 5] [1, 3, 5]

पूर्णांक अपरिवर्तनीय हैं, इसलिए आप एक नई वस्तु बनाए बिना मूल्य नहीं बदल सकते हैं:

>>> x = y = z = 1
>>> print(id(x), id(y), id(z))
507081216 507081216 507081216
>>> x = 2
>>> print(id(x), id(y), id(z))
507081248 507081216 507081216
>>> print(x, y, z)
2 1 1

1
idजरूरी नहीं कि मेमोरी लोकेशन हो। जैसा कि डॉक्स कहते हैं, यह "पहचान ... एक पूर्णांक ... लौटाता है, जो अपने जीवनकाल में इस वस्तु के लिए अद्वितीय और स्थिर रहने की गारंटी देता है।" सीपीथॉन स्मृति पते का उपयोग करने के लिए होता है id, लेकिन अन्य पायथन कार्यान्वयन नहीं हो सकते हैं। उदाहरण के लिए, PyPy नहीं है। और यह कहते हुए कि "दो वर्जन एक ही मेमोरी लोकेशन की ओर इशारा करते हैं" यह किसी को भी भ्रामक है जो इसे सी-स्टाइल समझता है। "एक ही वस्तु के दो नाम" अधिक सटीक और कम भ्रामक है।
abarnert

@abarnert स्पष्टीकरण के लिए धन्यवाद, मैंने जवाब अपडेट किया।
jurgenreza

7

अपने पहले उदाहरण में a = b = c = [1, 2, 3]आप वास्तव में कह रहे हैं:

 'a' is the same as 'b', is the same as 'c' and they are all [1, 2, 3]

यदि आप 'a' को 1 के बराबर, 'b' को '2' और 'c' के बराबर 3 पर सेट करना चाहते हैं, तो यह कोशिश करें:

a, b, c = [1, 2, 3]

print(a)
--> 1
print(b)
--> 2
print(c)
--> 3

उम्मीद है की यह मदद करेगा!


4

सीधे शब्दों में कहें, पहले मामले में, आप कई नामों को असाइन कर रहे हैं a list। सूची की केवल एक प्रति स्मृति में बनाई गई है और सभी नाम उस स्थान को संदर्भित करते हैं। इसलिए किसी भी नाम का उपयोग करके सूची को बदलना वास्तव में स्मृति में सूची को संशोधित करेगा।

दूसरे मामले में, स्मृति में एक ही मूल्य की कई प्रतियां बनाई जाती हैं। इसलिए प्रत्येक प्रति एक दूसरे से स्वतंत्र है।


3

आपको इसकी क्या आवश्यकता है:

a, b, c = [0,3,5] # Unpack the list, now a, b, and c are ints
a = 1             # `a` did equal 0, not [0,3,5]
print(a)
print(b)
print(c)

3

कोड जो मुझे चाहिए वह यह हो सकता है:

# test

aux=[[0 for n in range(3)] for i in range(4)]
print('aux:',aux)

# initialization

a,b,c,d=[[0 for n in range(3)] for i in range(4)]

# changing values

a[0]=1
d[2]=5
print('a:',a)
print('b:',b)
print('c:',c)
print('d:',d)

परिणाम:

('aux:', [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]])
('a:', [1, 0, 0])
('b:', [0, 0, 0])
('c:', [0, 0, 0])
('d:', [0, 0, 5])
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.