This may be a terrible idea (feel free to tell me if it is), but I'm exploring the boundaries of Python, and I could see how this could be useful (in fact, I'm looking at a potential case for it right now).
Here is the setup:
---(API File)---
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)
---- (My file) ----
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?
I want to modify the output of the api_function slightly, basically just to override the render function in the object it returns. I feel like my options are: (1, yuck) to copy the contents of api_function into my_function, but just construct and return a MyNode instead of an APINode, or (2, maybe?) to just call api_function from my_function, let its do its work--constructing and returning an object of type APINode, and then I can somehow create a MyNode from that object in order to override that one method.
It boils down to: In Python, is it possible to construct an instance of a child class from an instance of a parent class?
(Look familiar or wondering what the actual case is? I'm trying to extend a Django template tag.)
I think you'll be happier with MyNode wrapping APINode, rather than extending it. You can implement your own render() method, and delegate all others to the wrapped APINode. Then you'll be able to create a new MyNode from an existing APINode.
There's no way to make a child instance from a parent instance. The parent instance is an instance of APINode, you can't change an object's class.
Don't do this at home.
>>> 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 instead!
def render(self, arg1, arg2):
#My override of APINode's render
APINode.render = render
#congratulations, now APINode uses your render function.
This will still likely lead to hard-to-find bugs, but it's a bit cleaner.
Override the allocator.
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()
This is not something I would recommend, but anyways:
>>> 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 your particular case it would look like:
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__)
...
Here is a very simple and safe way of generating a new instance of a child class from a method of the parent class:
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
And you can check this in the terminal as follows:
>>> 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'>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With