2010-07-09 11 views
13

मैं क्लास में एक कन्स्ट्रक्टर को कॉल कर रहा हूं और यदि कोई निश्चित शर्त पूरी हो जाती है तो परिणामी वस्तु एक अलग वर्ग (कक्षाबी) का होना चाहती है। मैंने पहले तर्क को __init __() (नीचे दिए गए उदाहरण में 'स्वयं') __init __() के भीतर पहली तर्क को बदलने का प्रयास किया है, लेकिन ऐसा लगता है कि मैं जो चाहता हूं वह ऐसा नहीं लगता है।किसी भिन्न ऑब्जेक्ट के साथ __init __() में किसी उदाहरण को प्रतिस्थापित कैसे करें?

मुख्य में

:

import ClassA 

my_obj = ClassA.ClassA(500) 
# unfortunately, my_obj is a ClassA, but I want a ClassB! 
ClassA में

/__ init__.py:

import ClassB 

class ClassA: 
    def __init__(self,theirnumber): 
     if(theirnumber > 10): 
      # all big numbers should be ClassB objects: 
      self = ClassB.ClassB(theirnumber) 
      return 
     else: 
      # numbers under 10 are ok in ClassA. 
      return 

ClassB में/__ init__.py:

class ClassB: 
    pass 

उत्तर

27

आप उस के लिए __new__() की जरूरत है।

class ClassA(object): 
    def __new__(cls,theirnumber): 
     if theirnumber > 10: 
      # all big numbers should be ClassB objects: 
      return ClassB.ClassB(theirnumber) 
     else: 
      # numbers under 10 are ok in ClassA. 
      return super(ClassA, cls).__new__(cls, theirnumber) 

__new__() रन __init__() से पहले वर्ग इन्स्टेन्शियशन की प्रक्रिया के हिस्से के रूप में (और आप भी यह एक नई शैली वर्ग बनाने के लिए, आप अजगर 2 का उपयोग कर रहे, यह मानते हुए object उपवर्गीकरण द्वारा की जरूरत है।)। असल में __new__() वास्तव में नया उदाहरण बनाता है, और __init__() को इसके गुणों को आरंभ करने के लिए बुलाया जाता है। यही कारण है कि आप __new__() का उपयोग कर सकते हैं लेकिन __init__() नहीं बनाए गए ऑब्जेक्ट के प्रकार को बदलने के लिए: एक बार __init__() प्रारंभ होता है, ऑब्जेक्ट पहले से ही बनाया जा चुका है और इसके प्रकार को बदलने में बहुत देर हो चुकी है। (ठीक है ... वास्तव में नहीं, लेकिन यह बहुत आर्केन पायथन ब्लैक जादू में आता है।) the documentation देखें।

इस मामले में, हालांकि, मैं यह कहना चाहता हूँ एक कारखाने समारोह अधिक उपयुक्त है, जैसे

def thingy(theirnumber): 
    if theirnumber > 10: 
     return ClassB.ClassB(theirnumber) 
    else: 
     return ClassA.ClassA(theirnumber) 

वैसे कुछ, ध्यान दें कि एक ClassB है अगर यदि आप ऐसा क्या मैं ऊपर __new__() के साथ किया था, लौटा, ClassB उदाहरण की विधि नहीं कहा जाएगा! __new__() से लौटाई गई वस्तु उस कक्षा का एक उदाहरण है जिसमें __new__() विधि निहित है (यहां ClassA) पाइथन केवल __init__() पर कॉल करता है। फैक्ट्री फ़ंक्शन दृष्टिकोण के पक्ष में यह एक और तर्क है।

+0

ठीक है, अब क्या होगा यदि मैं ऑब्जेक्ट विधि के अंदर किसी ऑब्जेक्ट विधि के अंदर ऑब्जेक्ट को स्वैप करना चाहता हूं, तो कन्स्ट्रक्टर में? मैं एक वस्तु चाहता हूं जो अपने जीवन चक्र के दौरान अन्य वस्तुओं में बदल जाए। – sneak

+0

@ चुपके, आप नहीं कर सकते: विधि 'स्वयं' को एक तर्क के रूप में प्राप्त करती है और इसलिए जो भी वे ब्रेनैम कहने के लिए पुनरुत्थान कर सकते हैं, इसका विधि के बाहर कोई प्रभाव नहीं पड़ेगा। (आप निश्चित रूप से ** योग्य ** नाम जैसे 'स्वयं .__ वर्ग__' नामांकित कर सकते हैं - योग्य नाम और बैरेनम्स केवल हर सम्मान में बिल्कुल अलग हैं) जो आप सोच सकते हैं। –

+1

@ एलेक्स, तथ्य यह है कि आप 'स्वयं .__ वर्ग__' को असाइन कर सकते हैं, सीपीथॉन में कार्यान्वयन का दुर्घटना है; आधिकारिक पायथन spec का कहना है कि यह * काम नहीं करना चाहिए। यहां तक ​​कि अगर यह दुर्घटना नहीं थी, तो यह करने के लिए एक बहुत ही भयानक बात है। संक्षेप में: कृपया मत करो, और विशेष रूप से कृपया अन्य लोगों को यह सुझाव न दें। – habnabit

11

रचनाकारों के उद्देश्य को विकृत करने की कोशिश न करें: फ़ैक्टरी फ़ंक्शन का उपयोग करें। एक वर्ग के लिए एक कन्स्ट्रक्टर को कॉल करना और एक अलग वर्ग का उदाहरण लौटाया जाना भ्रम पैदा करने का एक निश्चित तरीका है।

+5

मुझे लगता है कि मैं unconfused, thx रहने के लिए प्रबंधित कर सकते हैं। – sneak

13

मैं इसके लिए फैक्टरी पैटर्न का उपयोग करने का सुझाव दूंगा। उदाहरण के लिए:

def get_my_inst(the_number): 
    if the_number > 10: 
     return ClassB(the_number) 
    else: 
     return ClassA(the_number) 

class_b_inst = get_my_inst(500) 
class_a_inst = get_my_inst(5) 
+1

यह करने के लिए यह "सही" तरीका है, IMHO। – ThatAintWorking

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

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