6 Stimmen

Python: Ist es möglich, eine Instanz einer Kindklasse aus einer Instanz einer Elternklasse zu konstruieren?

Dies kann eine schreckliche Idee sein (fühlen Sie sich frei, mir zu sagen, wenn es ist), aber ich bin die Grenzen von Python zu erkunden, und ich könnte sehen, wie dies nützlich sein könnte (in der Tat, ich bin an einem potenziellen Fall für sie gerade jetzt).

Hier ist der Aufbau:

---(API-Datei)---

class APINode(object):
    def __init__(self, *args, **kwargs):
        # initialize some instance variables

    def render(self, arg1, arg2):
        # do some stuff and return something

def api_function( arg1, arg2 ):
    # do some stuff
    return APINode(args, kwargs)

---- (Meine Datei) ----

class MyNode(APINode):
    def render(self, arg1, arg2):
        #My override of APINode's render 

def my_function( arg1, arg2 ):
    api_parent_instance = api_function( arg1, arg2 )
    #Can I some how create an instance of MyNode from api_parent_instance here?

Ich möchte die Ausgabe der api_function geringfügig ändern, im Grunde nur die Render-Funktion in das Objekt überschreiben es zurückgibt. Ich fühle mich wie meine Optionen sind: (1, igitt), um den Inhalt von api_function in my_function zu kopieren, aber nur konstruieren und zurückgeben ein MyNode anstelle eines APINode, oder (2, vielleicht?) nur api_function von my_function aufrufen, lassen Sie seine Arbeit tun--konstruieren und zurückgeben ein Objekt des Typs APINode, und dann kann ich irgendwie erstellen ein MyNode aus diesem Objekt, um diese eine Methode zu überschreiben.

Es läuft auf Folgendes hinaus: Ist es in Python möglich, eine Instanz einer untergeordneten Klasse aus einer Instanz einer übergeordneten Klasse zu konstruieren?

(Kommt Ihnen das bekannt vor oder fragen Sie sich, was der eigentliche Fall ist? Ich versuche, ein Django-Template-Tag zu erweitern).

7voto

Ned Batchelder Punkte 342778

Ich denke, Sie werden glücklicher mit MyNode Wrapping APINode, anstatt es zu erweitern. Sie können Ihre eigene render()-Methode implementieren und alle anderen an die umhüllte APINode delegieren. Dann werden Sie in der Lage sein, eine neue MyNode aus einem bestehenden APINode zu erstellen.

Es gibt keine Möglichkeit, eine Child-Instanz aus einer Parent-Instanz zu erzeugen. Die übergeordnete Instanz ist eine Instanz von APINode, man kann die Klasse eines Objekts nicht ändern.

2voto

ironchefpython Punkte 3391

Tun Sie das nicht zu Hause.

>>> class A:
...     def hi(self):
...         print "I am an A!"
... 
>>> class B:
...     def hi(self):
...         print "I am a B!"
... 
>>> a = A()
>>> a.hi()
I am an A!
>>> # Doing this will likely lead to hard to find bugs.
>>> a.__class__ = B
>>> a.hi()
I am a B!
>>> 

Monkey patch the API stattdessen!

def render(self, arg1, arg2):
    #My override of APINode's render 
APINode.render = render
#congratulations, now APINode uses your render function.

Dies wird wahrscheinlich immer noch zu schwer zu findenden Fehlern führen, aber es ist etwas sauberer.

1voto

Überschreiben Sie den Allokator.

class B(object):
  def __new__(cls, val):
    if val:
      return D()
    return super(B, cls).__new__(cls)

  def foo(self):
    return 'bar'

class D(object):
  def foo(self):
    return 'baz'

b1 = B(False)
b2 = B(True)
print b1.foo()
print b2.foo()

1voto

Mike Ivanov Punkte 919

Das würde ich zwar nicht empfehlen, aber egal:

>>> class Monkey(object):
...     def eat(self, smth):
...             if self.likes(smth):
...                     print "Yummy!"
...             else:
...                     print "Yuck!"
...     def likes(self, smth):
...             return smth == "banana"
... 
>>> m = Monkey()
>>> m.eat("banana")
Yummy!
>>> m.eat("cheezburger")
Yuck!
>>> def patch(self, smth):
...     return True
...
>>> m.likes = type(m.likes)(patch, m.likes, Monkey)
>>> m.eat("cheezburger")
Yummy!
>>> 

In Ihrem speziellen Fall würde das folgendermaßen aussehen:

def my_render(self, arg1, arg2):
    #My override of APINode's render 

def my_function( arg1, arg2 ):
    api_parent_instance = api_function( arg1, arg2 )
    api_parent_instance.render = type(api_parent_instance.render)(
        api_parent_instance,
        api_parent_instance.render,
        api_parent_instance.__class__)

    ...

1voto

galarant Punkte 1799

Hier ist eine sehr einfache und sichere Möglichkeit, eine neue Instanz einer Kindklasse aus einer Methode der Elternklasse zu erzeugen:

class Parent(object):
    def __init__(self):
        pass

    def generate_new_child_object(self):
        print "Generating a new object of type " + str(type(self))
        return type(self)()

class Child(Parent):
    pass

Sie können dies im Terminal wie folgt überprüfen:

>>> child = Child()
>>> type(child)
<class 'Child'>
>>> generated_child = child.generate_new_child_object()
Generating a new object of type <class 'Child'>
>>> type(generated_child)
<class 'Child'>

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X