2011-09-25 14 views
6

मैं अजगर के लिए नया हूं और सीखा है कि कक्षा विशेषताएँ सी ++ में स्थिर डेटा सदस्यों की तरह हैं। हालांकि, मैं निम्नलिखित कोड की कोशिश कर के बाद उलझन में मिल गया:पायथन: कक्षा विशेषताओं और उदाहरण विशेषताओं

>>> class Foo: 
...  a=1 
... 
>>> f1=Foo(); 
>>> f2=Foo() 
>>> f1.a 
1 
>>> f1.a=5 
>>> f1.a 
5 
>>> f2.a 
1 

नहीं चाहिए f2.a भी बराबर 5?

एक एक पूर्णांक के बजाय की एक सूची के रूप में परिभाषित किया जाता है, व्यवहार की उम्मीद है:

>>> class Foo: 
...  a=[] 
... 
>>> f1=Foo(); 
>>> f2=Foo() 
>>> f1.a 
[] 
>>> f1.a.append(5) 
>>> f1.a 
[5] 
>>> f2.a 
[5] 

मैं Python: Difference between class and instance attributes को देखा है, लेकिन यह मेरे सवाल का जवाब नहीं है।

कोई भी समझा सकता है कि अंतर क्यों? धन्यवाद

+0

संभावित डुप्लिकेट [मैं उदाहरणों के बीच पाइथन क्लास डेटा साझा करने से कैसे बचूं?] (Http: // stackoverflow।कॉम/प्रश्न/1680528/कैसे-करें-मैं-से बचने वाले-पायथन-कक्षा-डेटा-साझा-उदाहरणों के बीच) –

उत्तर

7

आप अपने दूसरे उदाहरण में एक ही बात नहीं कर रहे हैं। आप पहली बार उदाहरण में, आप f1.a एक नया मान निर्दिष्ट कर रहे हैं:

f1.a.append(5) 

यह परिवर्तन नहीं करता है क्या f1.a की ओर इशारा करते है:

f1.a = 5 

अपने दूसरे उदाहरण में, आप बस एक सूची का विस्तार कर रहे हैं। यदि आप इसे करने के बजाय थे:

f1.a = [5] 

आप पाएंगे कि यह आपके पहले उदाहरण के समान व्यवहार करता है।

लेकिन इस उदाहरण पर विचार करें:

>>> f1=Foo() 
>>> f2=Foo() 
>>> Foo.a = 5 
>>> f1.a 
5 
>>> f2.a 
5 

इस उदाहरण में, हम वास्तव में वर्ग विशेषता, का मूल्य बदल रहे हैं और परिवर्तन वर्ग के सभी मामलों में दिख रहा है।जब आप प्रकार:

f1.a = 5 

आप एक उदाहरण विशेषता के साथ वर्ग विशेषता अधिभावी कर रहे हैं।

+2

"आप एक आवृत्ति विशेषता के साथ कक्षा विशेषता को ओवरराइड कर रहे हैं।" मुझे ऐसा नहीं लगता। कक्षा विशेषता छूटी बनी हुई है। उपयोगकर्ता 1186 9 के कोड में, विशेषता ** एक ** निर्देश ''f1.a = 5'' द्वारा ** f1 ** के नम्पेस में बनाई गई है, क्योंकि यह विशेषता पहले मौजूद नहीं थी, क्योंकि यह है ** \ _ \ _ dict __ ** – eyquem

0

क्या होता है निम्नलिखित:

जब आप एक नया वस्तु f1 = Foo() का दृष्टांत, यह अपने आप में कोई गुण नहीं है।

print f1.__dict__ 
{'a': 5} 

:

print f1.__dict__ 
{} 

print f1.a 
1 

हालांकि, अगर आप f1.a = 5 निर्धारित करते हैं, उदाहरण है कि मूल्य का एक नई विशेषता हो जाता है: जब भी आप उदाहरण f1.a के लिए तक पहुँचने का प्रयास है, तो आप वर्ग के Foo.a पर पुनः निर्देशित हो किसी भी अन्य उदाहरण के रूप में, क्लास परिभाषा इस से छेड़छाड़ नहीं की जाती है।

दूसरे उदाहरण में, आप कुछ भी पुन: असाइन नहीं करते हैं। append के साथ आप केवल उसी ही सूची का उपयोग कर रहे हैं जिसे कक्षा में परिभाषित किया गया था। इसलिए, आपका उदाहरण अभी भी उस सूची को संदर्भित करता है, जैसा कि अन्य सभी उदाहरण करता है।

+1

उत्तर के समान ही मैं टाइप करने वाला था। मैं बस जोड़ता हूं कि यह एक सूची के साथ "काम करता है" कारण है क्योंकि उस स्थिति में वस्तु [mutable] (http://docs.python.org/library/stdtypes.html#typesseq-mutable) है। चूंकि सभी उदाहरण एक ही ऑब्जेक्ट को संदर्भित करते हैं, इसलिए उस ऑब्जेक्ट में संशोधनों को उनके द्वारा देखा जाता है। –

+0

@ डेबिलस्की: नए उदाहरणों में वास्तव में अक्सर अपने गुण होते हैं ('f1 .__ dict__' जो आप अपने उत्तर में लिखते हैं उनमें से एक है, जैसा कि आईडी आईडी (Foo.a)' और 'id (f1) की तुलना में देखा जा सकता है ए) ')। – EOL

5
>>> class Foo: 
...  a=1 
... 
>>> f1=Foo() 
>>> f2=Foo() 
>>> f1.a # no instance attribute here in f1, so look up class attribute in Foo 
1 
>>> f1.a=5 # create new instance attribute in f1 
>>> f1.a # instance attribute here. Great, let's use this. 
5 
>>> f2.a # no instance attribute in f2, look up class attribute in Foo 
1 
>>> 
>>> class Foo: 
...  a=[] 
... 
>>> f1=Foo() 
>>> f2=Foo() 
>>> f1.a   # no instance attribute - look up class attribute in Foo 
[] 
>>> f1.a.append(5) # no instance attribute, modify class attribute in-place 
>>> f1.a   # no instance attribute - look up class attribute in Foo 
[5] 
>>> f2.a   # same here 
[5] 
0

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

>>> f1.a=5 

ऑब्जेक्ट जिसमें विशेषता है, उदाहरण है, इसलिए यह उदाहरण है कि नया मान प्राप्त होता है।

3

मेरी सलाह: इस तरह के मामलों को समझने के लिए, ऐसा भी id, और __dict__ का उपयोग कर परीक्षण:

class Foo: 
    a=1 

# Foo.a == 1 
# id(Foo.a) == 10021840 
# Foo.__dict__ == {'a': 1, '__module__': '__main__', '__doc__': None} 


f1 = Foo() 

# f1.a == 1 
# id(f1.a) == 10021840 
# f1.__dict__ == {} 

f2 = Foo() 

# f2.a == 1 
# id(f2.a) == 10021840 
# f2.__dict__ == {} 

f1.a = 5 

# f1.a == 5 
# id(f1.a) == 10021792 
# f1.__dict__ == {'a': 5} 

# f2.a == 1 
# id(f2.a) == 10021840 
# f2.__dict__ == {} 

इससे पता चलता है कि जब तक शिक्षा f1.a = 5 निष्पादित नहीं किया गया है, उदाहरण के f1 एक भी नहीं है व्यक्तिगत विशेषता a

फिर, f1.a = 51 का उत्पादन करने से पहले निर्देश print f1.a क्यों निष्पादित किया गया है?
कारण है कि:

एक वर्ग उदाहरण एक namespace एक शब्दकोश जो पहले स्थान पर है, जिसमें संदर्भ विशेषता की खोज कर रहे हैं के रूप में लागू है। जब विशेषता वहां नहीं मिलती है, और इंस्टेंस की कक्षा में उस नाम से विशेषता है, तो खोज विशेषताओं के साथ जारी है।

http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy

9

पायथन के वर्ग गुण और वस्तु गुण अलग dictionaries में संग्रहीत हैं। ऑब्जेक्ट f1 के लिए, इन्हें क्रमशः f1.__class__.__dict__ और f1.__dict__ के माध्यम से एक्सेस किया जा सकता है। print f1.__class__ is Foo निष्पादित True आउटपुट करेगा।

जब आप किसी ऑब्जेक्ट की विशेषता का संदर्भ देते हैं, तो पायथन पहले ऑब्जेक्ट डिक्शनरी में इसे देखने का प्रयास करता है। यदि यह वहां नहीं मिलता है, तो यह कक्षा शब्दकोश (और विरासत विरासत पर) की जांच करता है।

जब आप f1.a पर असाइन करते हैं, तो आप f1 के लिए ऑब्जेक्ट डिक्शनरी में एक प्रविष्टि जोड़ रहे हैं। f1.a के बाद के लुकअप उस प्रविष्टि को पायेंगे। f2.a के लुकअप अभी भी वर्ग विशेषता - क्लास विशेषता शब्दकोश में प्रविष्टि पाएंगे।

आप f1.a का मूल्य इसे हटाकर 1 पर वापस लौटने के कारण बन सकते हैं:

del f1.a 

यह f1 की वस्तु शब्दकोश में a के लिए प्रवेश निकाल देंगे, और बाद में लुकअप वर्ग शब्दकोश में पर जारी रहेगा । तो, बाद में, print f1.a आउटपुट 1.

+0

का उपयोग करके मेरे उत्तर में दिखाया गया है मुझे लगता है कि यह उत्तर अधिक विस्तृत है – Yuncy

+0

@Yuncy मुझे लगता है – eyquem

संबंधित मुद्दे