2015-06-17 11 views
5

वारिस मैं इस तरह कुछ कोड है:अजगर वर्ग कारखाना यादृच्छिक माता पिता

class Person(object): 
    def drive(self, f, t): 
     raise NotImplementedError 

class John(Person): 
    def drive(self, f, t): 
     print "John drove from %s to %s" % (f,t) 

class Kyle(Person): 
    def drive(self, f, t): 
     print "Kyle drove from %s to %s" % (f,t) 

class RandomPerson(Person): 
    # instansiate either John or Kyle, and inherit it. 
    pass 

class Vehicle(object): 
    pass 

class Driver(Person, Vehicle): 
    def __init__(self): 
     # instantiate and inherit a RandomPerson somehow 
     pass 

d1 = Driver() 
d1.drive('New York', 'Boston') 
>>> "John drove from New York to Boston" 

d2 = Driver() 
d2.drive('New Jersey', 'Boston') 
>>> "Kyle drove from New Jersey to Boston" 

मैं RandomPerson कैसे लागू कर सकता है, निम्नलिखित आवश्यकताओं के साथ:

  • बुला person = RandomPerson() एक RandomPerson वस्तु लौट जाना चाहिए।
  • RandomPerson या तो John या Kyle यादृच्छिक रूप से उपclass करना चाहिए।
+2

एक यादृच्छिक वर्ग से विरासत के लिए, हालांकि पायथन में संभव है, आपकी समस्या का एक बहुत ही सरल समाधान नहीं लगता है: बस एक कारखाने समारोह का उपयोग करें। मैं एक फैक्ट्री फ़ंक्शन के साथ जाऊंगा जो यादृच्छिक रूप से आपके व्यक्ति वर्गों में से एक को तुरंत चालू करता है और उस उदाहरण को लौटाता है, उदा। वर्गों की सूची से यादृच्छिक रूप से कक्षा चुनकर। फ़ैक्टरी फ़ंक्शन पर कॉल आपके रैंडमपर्सन कन्स्ट्रक्टर कॉल की तरह दिखता है। –

+2

यह नहीं कि आपके वास्तविक प्रश्न के साथ इसका कोई संबंध नहीं है, लेकिन आपके पास अलग 'जॉन' और 'केली' ऑब्जेक्ट्स क्यों हैं? जॉन और केली नाम 'व्यक्ति' के गुण हैं (जैसे ऊंचाई/वजन/बालों का रंग/आंखों का रंग, आदि)। –

+0

@jacdeh मेरे लिए एक होमवर्क प्रश्न की तरह लगता है जिसे बुरी तरह से सूचित किया गया है (या तो प्रोफेसर या ओपी द्वारा)। –

उत्तर

1

अपने मूल जवाब में (जो मैं नष्ट कर दिया क्योंकि यह सिर्फ सादा गलत था) मैंने कहा कि मैं इस तरह कर रहा पर विचार करेंगे:

class RandomPerson(Person): 
    def __init__(self): 
     rand_person = random.choice((John, Kyle))() 
     self.__dict__ = rand_person.__dict__ 

इस तरह पाइथन Borg idiom का एक अनुकूलन है; विचार यह था कि किसी ऑब्जेक्ट के बारे में जो कुछ भी मायने रखता है वह __dict__ में निहित है।

हालांकि, यह केवल तभी काम करता है जब समान वर्ग (जो आप बोर्ग मुहावरे में कर रहे हैं) की ओवरराइटिंग ऑब्जेक्ट्स; ऑब्जेक्ट __dict__ में ऑब्जेक्ट क्लास से संबंधित राज्य जानकारी, ऑब्जेक्ट क्लास नहीं है।

यह तो जैसे एक वस्तु के वर्ग बाहर स्विच करने के लिए संभव है:

class RandomPerson(Person): 
    def __init__(self): 
     rand_person = random.choice((John, Kyle)) 
     self.__class__ = rand_person 

हालांकि, यह इस तरह से कर रही है मतलब यह होगा कि RandomPerson करने के लिए कॉल तो प्रति एक उदाहरण के लिए वापस नहीं होगा RandomPerson के अपने आवश्यकता, लेकिन Kyle या John का। तो यह कोई नहीं है।

यहाँ एक तरीका है कि में कार्य करता हैKyle या John की तरह एक RandomPerson वस्तु प्राप्त करने के लिए है, लेकिन नहीं है:

class RandomPerson(Person): 
    def __new__(cls): 
     new = super().__new__(cls) 
     new.__dict__.update(random.choice((Kyle,John)).__dict__) 
     return new 

यह एक - बहुत से यह कर को छोड़कर, बोर्ग मुहावरा के समान उदाहरण वस्तुओं के बजाए कक्षाएं और हम केवल चयनित कक्षा के वर्तमान संस्करण की प्रतिलिपि बना रहे हैं - वास्तव में बहुत बुरा है: हमने RandomPerson वर्ग को लॉबोटोमाइज्ड किया है और (यादृच्छिक रूप से) Kyle याके दिमाग को फंस गया है जगह में 0 वर्ग।और वहाँ कोई संकेत नहीं है, दुर्भाग्य से, कि यह हुआ:

>>> rperson = RandomPerson() 
>>> assert isinstance(rperson,Kyle) or isinstance(rperson,John) 
AssertionError 

तो हम अभी भी वास्तव में subclassed नहीं किया है Kyle या John। इसके अलावा, यह वास्तव में वास्तव में बुराई है। तो कृपया इसे तब तक न करें जब तक आपके पास वास्तव में कोई अच्छा कारण न हो।

अब, यह सोचते हैं आप वास्तव में एक अच्छा कारण है, इसके बाद के संस्करण समाधान काफी अच्छा होना चाहिए, अगर तुम सब के बाद कर रहे हैं सुनिश्चित करें कि आप Kyle या John से किसी भी वर्ग राज्य सूचना (तरीकों और वर्ग विशेषताएँ) का उपयोग कर सकते कर रही है RandomPerson के साथ। हालांकि, जैसा कि पहले बताया गया है, RandomPerson अभी भी एक वास्तविक उप-वर्ग नहीं है।

जैसा कि मैं कह सकता हूं कि वास्तव में यादृच्छिक रूप से किसी ऑब्जेक्ट की कक्षा को उपनिवेशित करने का कोई तरीका नहीं है और वर्ग को कई उदाहरण रचनाओं में राज्य बनाए रखने का कोई तरीका नहीं है। आपको इसे नकली करना होगा।

एक तरह से नकली करने के लिए इसे RandomPersonJohn और Kyleabstract baseclass module and __subclasshook__ का उपयोग कर, और अपने Person वर्ग को जोड़ने की एक उपवर्ग पर विचार किया जा करने की अनुमति है। ऐसा लगता है कि यह एक अच्छा समाधान होगा क्योंकि Person कक्षा एक इंटरफ़ेस है और इसका उपयोग सीधे नहीं किया जा रहा है, वैसे भी।

यहाँ ऐसा करने के लिए एक तरह से है: - हालांकि यह तकनीकी रूप से एक उपवर्ग नहीं है -

class Person(object): 
    __metaclass__ = abc.ABCMeta 
    def drive(self, f, t): 
     raise NotImplementedError 
    @classmethod 
    def __subclasshook__(cls, C): 
     if C.identity is cls: 
      return True 
     return NotImplemented 

class John(Person): 
    def drive(self, f, t): 
     print "John drove from %s to %s" % (f,t) 

class Kyle(Person): 
    def drive(self, f, t): 
     print "Kyle drove from %s to %s" % (f,t) 

class RandomPerson(Person): 
    identity = None 
    def __new__(cls): 
     cls.identity = random.choice((John,Kyle)) 
     new = super().__new__(cls) 
     new.__dict__.update(cls.identity.__dict__) 
     return new 

>>> type(RandomPerson()) 
class RandomPerson 
>>> rperson = RandomPerson() 
>>> isinstance(rperson,John) or isinstance(rperson,Kyle) 
True 

अब RandomPersonKyle या John का एक उपवर्ग, माना जाता है और यह भी राज्य के शेयरोंKyle या John का। वास्तव में, यह दो बार, यादृच्छिक रूप से, प्रत्येक बार एक नया उदाहरण बनाया जाता है (या जब RandomPerson.identity बदल जाता है) के बीच आगे और पीछे स्विच करेगा। चीजें इस तरह से कर रही है की एक और प्रभाव: यदि आप कई RandomPerson मामले हैं तो वे सब शेयर की जो कुछ भी RandomPerson उस क्षण में होने वाला राज्य - यानी, rperson1Kyle जा रहा है बाहर शुरू हो सकता है, और फिर rperson2 instantiated है जब , rperson2 और rperson1 दोनों John हो सकते हैं (या वे Kyle दोनों हो सकते हैं और फिर पर स्विच कर सकते हैं जब rperson3 बनाया गया है)।

कहने की जरूरत नहीं है, यह बहुत अजीब व्यवहार है। वास्तव में यह बहुत अजीब है, मेरा संदेह यह है कि आपके डिजाइन को एक पूर्ण ओवरहाल की आवश्यकता है। मुझे सच में नहीं लगता कि ऐसा करने के लिए बहुत अच्छा कारण है (शायद किसी पर बुरा मजाक बजाए)।

आप अपने Person वर्ग में इस व्यवहार मिश्रण नहीं करना चाहते हैं, तो आप भी इसे अलग कर सकता है:

class Person(object): 
    def drive(self, f, t): 
     raise NotImplementedError 

class RandomPersonABC(): 
    __metaclass__ = abc.ABCMeta 
    @classmethod 
    def __subclasshook__(cls, C): 
     if C.identity is cls: 
      return True 
     return NotImplemented 

class John(Person, RandomPersonABC): 
    def drive(self, f, t): 
     print "John drove from %s to %s" % (f,t) 

class Kyle(Person, RandomPersonABC): 
    def drive(self, f, t): 
     print "Kyle drove from %s to %s" % (f,t) 

class RandomPerson(Person): 
    identity = None 
    def __new__(cls): 
     cls.identity = random.choice((John,Kyle)) 
     new = super().__new__(cls) 
     new.__dict__.update(cls.identity.__dict__) 
     return new 
+0

मैं ऑब्जेक्ट की कक्षा को बदलने के साथ जा रहा हूं, जैसा आपने बताया: 'rand_person = random.choice ((जॉन, केली)) 'और' self .__ class__ = rand_person'। मैंने 'रैंडमपर्सन' के तरीकों को 'व्यक्ति' में वापस ले जाया है, और 'रैंडमपर्सन' अब फैक्ट्री-आईएसएच जनरेटिंग क्लास की तरह काम करता है। आपके इनपुट के लिए धन्यवाद! – user37203

1

तुम बस RandomPerson वर्ग को लागू कर सकता है एक सदस्य के लिए _my_driver कहा जाता है या आप चाहते थे और जो कुछ भी। आप RandomPerson.drive विधि से बस अपनी drive विधि को कॉल करेंगे। यह कुछ इस तरह दिख सकता है: वैकल्पिक रूप से

class RandomPerson(Person): 
    # instantiate either John or Kyle, and inherit it. 
    def __init__(self): 
     self._my_person = John() if random.random() > 0.50 else Kyle() 
    def drive(self, f, t): 
     self._my_person.drive(f,t) 

, अगर आप यह सुनिश्चित करें कि वर्ग Kyle या John के रूप में वास्तव में एक ही तरीके का है बनाने के बारे में अधिक सख्त होना चाहते हैं, तो आपको निम्न की तरह निर्माता में विधि सेट कर सकते हैं :

class RandomPerson(Person): 
    # instantiate either John or Kyle, and inherit it. 
    def __init__(self): 
     self._my_person = John() if random.random() > 0.50 else Kyle() 
     self.drive = self._my_person.drive 
+0

'रैंडमर्सन' रखने का क्या मतलब है 'व्यक्ति', यदि उसके पास '_my_person' विशेषता है? विरासत व्यर्थ हो जाता है। साथ ही, 'ड्राइव' फ़ंक्शन दो 'केली' और 'जॉन' कक्षाओं में अलग है, और अधिक, ड्राइव अन्य कार्यों को संदर्भित करता है जो 'जॉन' और 'केली' के लिए कस्टम हैं। – user37203

0

अपने में most recent comment on my other answer आप ने कहा:

मुझे जाना जा रहा हूँ ऑब्जेक्ट की कक्षा को बदलने के साथ, जैसा कि आपने बताया: rand_person = random.choice((John, Kyle)) और self.__class__ = rand_person। मैंने RandomPerson के तरीकों को Person में वापस ले जाया है, और RandomPerson फ़ैक्टरी-आईएसएच जनरेटिंग क्लास की तरह काम करता है।

यदि मैं ऐसा कह सकता हूं, तो यह एक अजीब विकल्प है। सबसे पहले, ऑब्जेक्ट सृजन के बाद वर्ग को स्वैप करना बहुत पाइथनिक नहीं लगता है (यह अत्यधिक जटिल है)। बेहतर होगा वस्तु दृष्टान्त उत्पन्न करने के लिए बेतरतीब ढंग से करने के बजाय इस तथ्य के बाद वर्ग बताए हैं:

class RandomPerson(): # Doing it this way, you also don't need to inherit from Person 
    def __new__(self): 
     return random.choice((Kyle,John))() 

दूसरे, यदि कोड ताकि आप उसकी कोई भी RandomPerson वस्तु की आवश्यकता होती है पुनर्संशोधित किया गया है, यही कारण है कि एक सब पर है?

def RandomPerson(): 
    return random.choice((Kyle,John))() 
+0

अच्छी तरह से 'रैंडमपर्सन' को बाद में अन्य वर्गों द्वारा विरासत में मिला है, और मुझे इसे भरोसेमंद और कंटेनरकृत करने की आवश्यकता है .. कहीं भी प्रयोग योग्य। कक्षाओं और उदाहरणों के नाम बेवकूफ लगते हैं, लेकिन मैंने इसे कागज पर काम किया है और मेरी वास्तविक समस्या के लिए कोई और तरीका नहीं है। मुझे 'रैंडमपर्सन' का उत्तराधिकारी होना चाहिए, न कि 'व्यक्ति' जो किसी और चीज में बदल जाता है ('जॉन' या 'केली' में)। उम्मीद है कि यह समझ में आता है। – user37203

+0

आप अमूर्त बेसक्लास के लाभों में थोड़ा गहराई से देखना चाहते हैं। इस तरह की चीज वह है जिसे वे बनाए गए थे। इसके बारे में सोचने की एक और बात: एक ऑब्जेक्ट को किसी अन्य ऑब्जेक्ट में "ट्रांसफॉर्म करना" ऐसा लगता है जो स्पष्ट रूप से किया जाना चाहिए, न कि पृष्ठभूमि में/पृष्ठभूमि में। एक विधि के माध्यम से इसे करने पर विचार करें - उदा। 'रैंडमपर्सन()। Get_real_person() '- या कुछ। –

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