2012-01-02 13 views
26

मुझे यह समझने में समस्या है कि क्लास/इंस्टेंस चर कैसे पाइथन में काम करते हैं। मैं समझता हूँ कि जब मैं इस कोड की कोशिश सूची चर एक वर्ग चर हो रहा है नपायथन क्लास इंस्टेंस वैरिएबल और क्लास वेरिएबल्स

class testClass(): 
    list = [] 
    def __init__(self): 
     self.list.append('thing') 

p = testClass() 
print p.list 

f = testClass() 
print f.list 

उत्पादन:

['thing'] 
['thing', 'thing'] 

और यह एक उदाहरण चर हो रहा है जब मैं यह कर

class testClass(): 
    def __init__(self): 
     self.list = [] 
     self.list.append('thing') 

p = testClass() 
print p.list 

f = testClass() 
print f.list 

उत्पादन:

['thing'] 
['thing'] 

बहुत धन्यवाद

जॉन

+1

यदि मैं सही ढंग से समझता हूं, तो आप पाइथन के वाक्यविन्यास के बारे में विशेष डिजाइन निर्णय के पीछे तर्क के लिए पूछ रहे हैं। ऐसे प्रश्नों के लिए, सबसे अच्छा जवाब या तो "क्योंकि यह भाषा की भावना के साथ फिट बैठता है", या अधिक स्पष्ट रूप से: "अपने निर्माता से पूछें"। – Xion

+0

ठीक है तो वैरिएबल डिफ़ॉल्ट रूप से क्लास वेरिएबल्स हैं, जहां मेरा भ्रम है, जो मेरा प्रश्न होना चाहिए था, क्लास वेरिएबल्स –

+4

@jonathantopf नहीं के लिए चर वैरिएबल करें, चर डिफ़ॉल्ट रूप से कक्षा चर नहीं हैं। पायथन में आप varables घोषित नहीं करते हैं। उस मामले के लिए, वे वास्तव में चर नहीं हैं (पायथन एक _variableless_ lanuage है), बस नाम। और आप नामों की घोषणा या आकलन नहीं करते हैं, तो आप उन्हें किसी ऑब्जेक्ट पर _bind_ करते हैं। और रनटाइम में प्रत्येक ऑब्जेक्ट में नाम-से-ऑब्जेक्ट का शब्दकोश होता है। और यहां तक ​​कि यदि दो वस्तुएं एक ही कक्षा के हैं, तो उनके पास बहुत अलग शब्दकोश हो सकते हैं। – rodrigo

उत्तर

40

इसका कारण यह है जिस तरह से अजगर . साथ नाम का समाधान करता है। जब आप self.list लिखते हैं तो पाइथन रनटाइम list नाम को पहले उदाहरण ऑब्जेक्ट में ढूंढने का प्रयास करता है, और यदि क्लास इंस्टेंस में नहीं मिलता है।

की इस पर गौर करते हैं कदम

self.list.append(1) 
  1. द्वारा कदम वहाँ वस्तु self में एक list नाम है?
    • हाँ: इसका उपयोग करें! समाप्त।
    • नहीं: करने के लिए 2.
  2. जाओ वहाँ वस्तु self के वर्ग उदाहरण में एक list नाम है?
    • हाँ: इसका उपयोग करें!
    • समाप्त करें: त्रुटि!

लेकिन जब आप एक नाम बातें बाँध अलग हैं:

self.list = [] 
  1. वहाँ वस्तु self में एक list नाम है?
    • हाँ: इसे ओवरराइट करें!
    • नहीं: इसे बांधें!

तो, कि हमेशा एक उदाहरण चर रहा है।

आपका पहला उदाहरण कक्षा उदाहरण में list बनाता है, क्योंकि यह उस समय सक्रिय दायरा है (कहीं भी self कहीं भी)। लेकिन आपका दूसरा उदाहरण को self के दायरे में स्पष्ट रूप से बनाता है।

class testClass(): 
    list = ['foo'] 
    def __init__(self): 
     self.list = [] 
     self.list.append('thing') 

x = testClass() 
print x.list 
print testClass.list 
del x.list 
print x.list 

कि प्रिंट होगा:

['thing'] 
['foo'] 
['foo'] 

जैसे ही आप उदाहरण के नाम वर्ग के नाम self संदर्भ के माध्यम से दिखाई दे रहा है को नष्ट

अधिक दिलचस्प उदाहरण होगा।

+0

ठीक है, मैं उस मामले में __init__ फ़ंक्शन के बाहर आवृत्ति चर को परिभाषित करने का कोई तरीका है, मैंने अभी __init__ के बाहर 'self.list [] 'करने का प्रयास किया है, यह समझ में आता है लेकिन क्या कोई तरीका है? –

+0

@jonathantopf: इंस्टेंस वैरिएबल केवल तभी बनाया जा सकता है जब आपके पास कोई उदाहरण हो। उन्हें एक विधि में बनाया जाना है जिसे इंस्टेंट पर बुलाया जाता है। आपका दूसरा विकल्प '__new__' को अधिभारित करना है और उन्हें वहां बनाना है, लेकिन यह वास्तव में बदसूरत है क्योंकि यह वास्तव में '__new__' नहीं है, और यह वास्तव में' __init__' में बनाने से बेहतर नहीं है। क्या, प्रार्थना करें, क्या आपको लगता है कि आपको इस क्षमता की आवश्यकता है? आप एक मेटा-क्लास बना सकते हैं जो कक्षा के निर्देश को देखने के लिए '__new__' ओवरलोड करता है और चीजों को उदाहरण के लिए प्रतिलिपि बनाता है। लेकिन यह ** वास्तव में ** बदसूरत है। – Omnifarious

+0

:) बिंदु ले लिया, यह समझ में आता है, मुझे इस तरह के प्रश्न पूछने से नफरत है, लेकिन कभी-कभी यह पता लगाने का सबसे अच्छा तरीका है कि क्या सोच रहा है कि पागल है या नहीं, अब मुझे पता है! –

0

जब आप कक्षा को तुरंत चालू करते हैं, __init__ विधि स्वचालित रूप से निष्पादित की जाती है।

पहली बार आपकी सूची एक वर्ग विशेषता है और इसके सभी उदाहरणों द्वारा साझा की जाती है। आपको दो चीजें मिल गईं क्योंकि आपने p को तत्काल करते समय एक और एक और जोड़ा जब तत्काल f (पहला वाला पहले कॉल पर पहले से जोड़ा गया था)।

3

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

>>> class testClass(): 
...  list = [] 
...  def __init__(self): 
...    self.list.append("thing") 
... 
>>> testClass.list 
[] 
>>> testClass.list.append(1) 
>>> testClass.list 
[1] 

लेकिन सभी वस्तुओं वर्ग और एक दूसरे के साथ list विशेषता का हिस्सा:

>>> testObject = testClass() 
>>> testObject.list 
[1, 'thing'] 
>>> testClass.list 
[1, 'thing'] 
>>> 
>>> testObject2 = testClass() 
>>> testClass.list 
[1, 'thing', 'thing'] 
>>> testObject2.list 
[1, 'thing', 'thing'] 
4

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

class testClass(): 
    l = [] 
    def __init__(self): 
     self.l = ['fred'] 

यह प्रत्येक उदाहरण के एक चर l कहा जाता है दे देंगे कि मास्क वर्ग चर l। यदि आप self.__class__.l करते हैं तो भी आप क्लास वैरिएबल पर पहुंच पाएंगे।

जिस तरह से मुझे लगता है यह है ... जब भी आप instance.variable (विधि नामों के लिए भी, वे केवल वेरिएबल्स हैं जो फ़ंक्शन होने के लिए होते हैं) यह उदाहरण के शब्दकोश में दिखता है। और अगर इसे वहां नहीं मिल रहा है, तो यह इसे उदाहरण के वर्ग 'शब्दकोश में देखने की कोशिश करता है। यह तभी होता है जब चर 'पढ़ा जा रहा हो'। यदि इसे असाइन किया जा रहा है, तो यह हमेशा इंस्टेंस डिक्शनरी में एक नई प्रविष्टि बनाता है।

+0

क्या विचलित जटिलताओं! यह जवाब वास्तव में सहायक था, क्योंकि 'रीडिंग बनाम लेखन' का मामला मुझे सिरदर्द दे रहा था। – dotslash

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