2009-07-04 3 views
8

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

A = Parent(x, y, z) 
B = Child(A) 

यह एक हैक है कि मैंने सोचा था कि काम हो सकता है है:

class Parent(object): 

    def __init__(self, x, y, z): 
     print "INITILIZING PARENT" 
     self.x = x 
     self.y = y 
     self.z = z 

class Child(Parent): 

    def __new__(cls, *args, **kwds): 
     print "NEW'ING CHILD" 
     if len(args) == 1 and str(type(args[0])) == "<class '__main__.Parent'>": 
      new_args = [] 
      new_args.extend([args[0].x, args[0].y, args[0].z]) 
      print "HIJACKING" 
      return Child(*new_args) 
     print "RETURNING FROM NEW IN CHILD" 
     return object.__new__(cls, *args, **kwds) 

लेकिन जब मैं

B = Child(A) 

चलाने मैं:

NEW'ING CHILD 
HIJACKING 
NEW'ING CHILD 
RETURNING FROM NEW IN CHILD 
INITILIZING PARENT 
Traceback (most recent call last): 
    File "classes.py", line 52, in <module> 
    B = Child(A) 
TypeError: __init__() takes exactly 4 arguments (2 given) 

ऐसा लगता है हैक काम करता है जैसा कि मैंने उम्मीद की थी लेकिन संकलक एक टी फेंकता है अंत में ypeError। मैं सोच रहा था कि क्या मैं बी = चाइल्ड (ए) मुहावरे को अनदेखा करने के लिए TypeError को अधिभारित कर सकता हूं लेकिन मुझे यकीन नहीं था कि यह कैसे करें। किसी भी मामले में, क्या आप कृपया उदाहरणों से विरासत के लिए अपने समाधान दें?

धन्यवाद!

+1

बस एक एफवाईआई, "प्रारंभिक" में 'ए' के ​​साथ लिखा गया है। इसे संपादित करने का प्रयास किया लेकिन StackOverflow 6 अक्षरों से कम संपादन की अनुमति नहीं देगा। – cfwschmidt

उत्तर

7

एक बार वर्ग Child में __new__Child का एक उदाहरण देता है, Child.__init__ कहा जाएगा कि उदाहरण पर (एक ही तर्क __new__ दिया गया था के साथ) - और जाहिरा तौर पर यह सिर्फ Parent.__init__ विरासत है, जो अच्छी तरह से बस के साथ बुलाया जा रहा है के लिए नहीं ले करता है एक तर्क (अन्य Parent, A)।

अगर कोई अन्य तरीके से एक Child बनाया जा सकता है, तो आप एक Child.__init__ है कि या तो एक आर्ग (यह ध्यान नहीं देता है) या तीन (जिस स्थिति में यह Parent.__init__ कॉल) स्वीकार करता है परिभाषित कर सकते हैं। लेकिन __new__ से आगे बढ़ना आसान है और Child.__init__ में सभी तर्क हैं, बस Parent.__init__ उचित रूप से कॉल करें!

एक कोड उदाहरण के साथ इस ठोस बनाने के लिए:

class Parent(object): 

    def __init__(self, x, y, z): 
     print "INITIALIZING PARENT" 
     self.x = x 
     self.y = y 
     self.z = z 

    def __str__(self): 
     return "%s(%r, %r, %r)" % (self.__class__.__name__, 
      self.x, self.y, self.z) 


class Child(Parent): 

    _sentinel = object() 

    def __init__(self, x, y=_sentinel, z=_sentinel): 
     print "INITIALIZING CHILD" 
     if y is self._sentinel and z is self._sentinel: 
      print "HIJACKING" 
      z = x.z; y = x.y; x = x.x 
     Parent.__init__(self, x, y, z) 
     print "CHILD IS DONE!" 

p0 = Parent(1, 2, 3) 
print p0 
c1 = Child(p0) 
print c1 
c2 = Child(4, 5, 6) 
print c2 
3

आप बच्चे के लिए एक निर्माता (init) को परिभाषित नहीं है, इसलिए माता पिता निर्माता कहा जाता है, 4 तर्क की उम्मीद है, जबकि केवल 2 में पारित कर रहे हैं (नए से)। आप जो चाहते हैं उसे पूरा करने का एक तरीका यहां दिया गया है:

class Child(Parent): 
    def __init__(self, *args, **kwargs): 
     if len(args) == 1 and isinstance(args[0], Parent): 
      Parent.__init__(self, args[0].x, args[0].y, args[0].z) 

     else: 
      # do something else 
+0

+1: केवल माता-पिता के गुणों की प्रतिलिपि बनाकर एक बच्चा बनाएं। –

0

धन्यवाद, दोस्तों, वह जल्दी था! मैं पहली बार एलेक्स की टिप्पणी पढ़ सकते हैं और मैं दुबारा लिखा बच्चे की __init__ रूप

def __init__(self, *args, **kwds): 
    if len(args) == 1 and str(type(args[0])) == "<class '__main__.Parent'>": 
     new_args = [args[0].x, args[0].y, args[0].z] 
     super(Child, self).__init__(*new_args, **kwds) 
    else: 
     super(Child, self).__init__(*args, **kwds) 

जो बहुत क्या सुझाव दिया abhinavg के समान है (के रूप में मैं सिर्फ पता चला)। और यह काम करता है। केवल उसकी और ars '

if len(args) == 1 and isinstance(args[0], Parent): 

मेरा से क्लीनर है।

धन्यवाद फिर से !!

5

ठीक है, इसलिए मुझे एहसास नहीं हुआ कि आप तर्कों की स्थिर प्रतिलिपि से खुश हैं जब तक कि मैं पहले से ही अपने समाधान के साथ आधे रास्ते में नहीं था। लेकिन मैंने इसे बर्बाद न करने का फैसला किया, तो यहां वैसे भी है। अन्य समाधानों से अंतर यह है कि वास्तव में माता-पिता से गुण प्राप्त किए जाएंगे, भले ही वे अपडेट हों।

_marker = object() 

class Parent(object): 

    def __init__(self, x, y, z): 
     self.x = x 
     self.y = y 
     self.z = z 

class Child(Parent): 

    _inherited = ['x', 'y', 'z'] 

    def __init__(self, parent): 
     self._parent = parent 
     self.a = "not got from dad" 

    def __getattr__(self, name, default=_marker): 
     if name in self._inherited: 
      # Get it from papa: 
      try: 
       return getattr(self._parent, name) 
      except AttributeError: 
       if default is _marker: 
        raise 
       return default 

     if name not in self.__dict__: 
      raise AttributeError(name) 
     return self.__dict__[name] 

हम ऐसा अब अगर:

>>> A = Parent('gotten', 'from', 'dad') 
>>> B = Child(A) 
>>> print "a, b and c is", B.x, B.y, B.z 
a, b and c is gotten from dad 

>>> print "But x is", B.a 
But x is not got from dad 

>>> A.x = "updated!" 
>>> print "And the child also gets", B.x 
And the child also gets updated! 

>>> print B.doesnotexist 
Traceback (most recent call last): 
    File "acq.py", line 44, in <module> 
    print B.doesnotexist 
    File "acq.py", line 32, in __getattr__ 
    raise AttributeError(name) 
AttributeError: doesnotexist 

इस का एक अधिक सामान्य संस्करण के लिए, http://pypi.python.org/pypi/Acquisition पैकेज को देखो। वास्तव में, कुछ मामलों में एक खूनी आवश्यकता समाधान है।

2

मुझे पता है कि यह एक बेहद पुराना धागा है, लेकिन मैंने हाल ही में अलेक्जेंड्रा के समान चुनौती में भाग लिया, और यह मुझे सबसे ज्यादा प्रासंगिक विषय था। मेरे पास कई सारे गुणों के साथ एक अभिभावक वर्ग था, और मैं अनिवार्य रूप से इसके सभी तरीकों और विशेषताओं को ध्यान में रखते हुए, कुछ जोड़ना और संशोधित/ओवरराइटिंग करना चाहता था। एक सरल सबक्लास काम नहीं करेगा क्योंकि उपयोगकर्ता रनटाइम के दौरान उपयोगकर्ता द्वारा भरा जाएगा, और मैं केवल मूल वर्ग से डिफ़ॉल्ट मानों का उत्तराधिकारी नहीं कर सका। बहुत सारे टिंकरिंग के बाद मुझे __new__ का उपयोग कर ऐसा करने के लिए एक बहुत साफ (हालांकि हैकी) तरीका मिला। यहाँ एक उदाहरण है:

class Parent(object): 
    def __init__(self): 
     # whatever you want here 
     self.x = 42 
     self.y = 5 
    def f(self): 
     print "Parent class, x,y =", self.x, self.y 

class Child(Parent): 
    def __new__(cls, parentInst): 
     parentInst.__class__ = Child 
     return parentInst 
    def __init__(self, parentInst): 
     # You don't call the Parent's init method here 
     self.y = 10 
    def f(self): 
     print "Child class, x,y =", self.x, self.y 

c = Parent() 
c.f() # Parent class, x,y = 42 5 
c.x = 13 
c.f() # Parent class, x,y = 13 5 
c = Child(c) 
c.f() # Child class, x,y = 13 10 

केवल विशेष हिस्सा बच्चे की निर्माता में जनक वर्ग के __class__ विशेषता बदल रहा है। इस वजह से, बच्चे की __init__ विधि को सामान्य के रूप में बुलाया जाएगा, और मेरे ज्ञान के लिए बाल वर्ग को किसी अन्य विरासत वर्ग के रूप में कार्य करना चाहिए।

class Child(object): 
    def __init__(self): 
     self.obj = Parent() 

    def __getattr__(self, attr): 
     return getattr(self.obj, attr) 

इस तरह से आप सभी अभिभावकों की विधि और विरासत की समस्याओं में चलने के बिना अपने स्वयं के उपयोग कर सकते हैं:

+1

मैं कुछ इसी तरह से भाग गया: http://stackoverflow.com/questions/14177788/init-child-with-parent-instance – elyase

2

मैं स्पष्ट तरीका होने के लिए इस (कैप्सूलीकरण) पाते हैं।