2012-01-14 6 views
6

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

कहते हैं कि हम एक सरल वस्तु है:

class Spam(object): 
    eggs = {} 

    def __init__(self, bacon_type): 
     self.eggs["bacon"] = bacon_type 

    def __str__(self): 
     return "My favorite type of bacon is " + self.eggs["bacon"] 

और हम अलग तर्क के साथ इस वस्तु के दो उदाहरणों बनाएँ:

spam1 = Spam("Canadian bacon") 
spam2 = Spam("American bacon") 

print spam1 
print spam2 

परिणाम puzzling हैं:

My favorite type of bacon is American bacon 
My favorite type of bacon is American bacon 

यह ऐसा लगता है कि "अंडे" शब्दकोश को सभी अलग-अलग "स्पैम" उदाहरणों के बीच साझा किया जाता है - या तो वह या यह है जब भी एक नया उदाहरण बनाया जाता है तो ओवरराइट किया जाता है। के बाद से हम इसे प्रारंभ समारोह में उदाहरण चर की घोषणा के द्वारा हल कर सकते हैं यह वास्तव में हर दिन जीवन में एक समस्या यह है,:

class Spam(object): 

    def __init__(self, bacon_type): 
     self.eggs = {} 
     self.eggs["bacon"] = bacon_type 

    def __str__(self): 
     return "My favorite type of bacon is " + self.eggs["bacon"] 

spam1 = Spam("Canadian bacon") 
spam2 = Spam("American bacon") 

print spam1 
print spam2 
इस तरह से लिखा कोड के साथ

, परिणाम हम क्या उम्मीद है:

My favorite type of bacon is Canadian bacon 
My favorite type of bacon is American bacon 

इसलिए जब मैं इस व्यवहार से नहीं हूं, मुझे समझ में नहीं आता कि पाइथन इस तरह क्यों काम करता है। क्या कोई इस पर रोशनी डाल सकता है?

+0

के संभावित डुप्लिकेट [मैं अजगर वर्ग डेटा उदाहरणों के बीच साझा होने से कैसे बच सकता हूं?] (Http://stackoverflow.com/questions/1680528/how-do-i-avoid-having-python-class-data-shared -मोंग-इंस्टेंस) –

उत्तर

7

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

एक और नोट पर: ऐसा लगता है जैसे आप जावा (या जावा-जैसे) परिप्रेक्ष्य से इस पर आ रहे हैं। तो शायद आप जानते हैं कि जावा को स्पष्ट रूप से घोषित करने के लिए चर की आवश्यकता होती है, इसके लिए कक्षा के दायरे में आवृत्ति परिवर्तनीय घोषणाएं होती हैं।

class Foo { 
    String bar; 
    public Foo() { 
     this.bar = "xyz"; 
    } 
} 

ध्यान दें कि केवल घोषणा वर्ग दायरे में है। दूसरे शब्दों में, मेमोरी उस चर के लिए आवंटित वर्ग "टेम्पलेट" का हिस्सा है, लेकिन वास्तविक वैरिएबल वैरिएबल नहीं है।

पायथन को परिवर्तनीय घोषणाओं की कोई आवश्यकता नहीं है। तो पायथन अनुवाद में, आप बस घोषणा छोड़ दें।

class Foo: 
    # String bar; <-- useless declaration is useless 
    def __init__(self): 
     self.bar = "xyz" 

स्मृति जब यह आवश्यक है आवंटित किया जाएगा; केवल असाइनमेंट वास्तव में लिखा गया है। और वह जावा में बस कन्स्ट्रक्टर में जाता है।

+0

हां, बिल्कुल - जब मैंने कॉलेज में ओओपी लिया, तो हमने इसे जावा में किया। –

5

यह एक उदाहरण चर नहीं है, यह एक वर्ग चर है। तथ्य यह है कि इसे किसी उदाहरण के माध्यम से एक्सेस किया जा रहा है अप्रासंगिक है; यह अभी भी वही वस्तु है।

+0

मुझे वह मिल रहा है जो आप कह रहे हैं। लेकिन, एक वर्ग को परिभाषित करते समय, आप आवृत्ति चर या वर्ग चर के रूप में चर कैसे घोषित करते हैं? मेरा मतलब है कि जब आप इस कोड को देखते थे तो यह कैसे पता चला कि यह एक वर्ग चर था? – Divya

+2

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

+0

ठीक है, तो अगर मैं आपको स्पैम उदाहरण बना देता हूं, तो मैं स्पैम.ईग्स को सीधे कॉल कर सकता हूं और स्पैम इंस्टेंस के अंडे को अभी प्राप्त कर सकता हूं? आपकी सहायताके लिए धन्यवाद! –

2

एक संकलित भाषा में विपरीत, पायथन में class बयान वास्तव में कोड है कि निष्पादित करता है, और एक वर्ग वस्तु (नहीं एक उदाहरण!) स्मृति में पैदा करता है।

class ब्लॉक रनों के दौरान परिभाषित किए गए किसी भी प्रतीक वर्ग से संबंधित हैं।इसमें आपके पहले उदाहरण में eggs चर के साथ-साथ __init__ और __str__ विधियों को परिभाषित करने वाले चर शामिल हैं। उन सभी को तब बनाया जाता है जब कक्षा परिभाषित की जाती है, और वे कक्षा के सभी भाग हैं। जब तक आप वास्तव में वस्तु का एक उदाहरण बनाने

उदाहरण चर बनाई गई हैं नहीं, और __init__ विधि चलाया जाता है, और वे है self की विशेषताओं होने के लिए।

तो, जब अजगर दुभाषिया कार्यान्वित

class Spam(object): 
    eggs = {} 

    def __init__(self): 
     <stuff> 
    def __str__(self): 
     <other stuff> 

यह वास्तव में रन टाइम पर एक वर्ग वस्तु बनाने जा रहा है। यह कोड "eggs={}" निष्पादित करता है, और यह दो def कथन निष्पादित करता है, और यह एक वर्ग बनाता है जिसमें तीन विशेषताएं हैं: eggs, __init__ और __str__

बाद में, जब वह निष्पादित

spam1 = Spam() 

तो यह एक नया उदाहरण बनाता है, और इसके __init__ विधि चलाता है। __init__ विधि स्वयं, कक्षा से संबंधित है; यह सभी उदाहरणों के बीच साझा किया जाता है, जैसे कि eggs विशेषता।

उदाहरण स्वयं self पैरामीटर के रूप में पारित हो जाता है, और जो भी आप इसे परिभाषित करते हैं वह उस उदाहरण से संबंधित है। यही कारण है कि self को हर वर्ग विधि में पारित किया जाना है - पायथन में, वास्तव में कक्षाएं स्वयं के वर्ग से संबंधित हैं, और self एकमात्र तरीका है जिसे आपको उदाहरण का संदर्भ देना है।

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