13

I would like to know how to convert parent object that was return by some function to child class.

class A(object):
    def __init__():
        pass

class B(A):
    def functionIneed():
        pass

i = module.getObject() # i will get object that is class A
j = B(i) # this will return exception
j.functionIneed()

I cannot change class A. If I could I would implement functionIneed to class A, but it is impossible because of structure of code.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Tomas
  • 331
  • 1
  • 3
  • 10

7 Answers7

25

Python does not support "casting". You will need to write B.__init__() so that it can take an A and initialize itself appropriately.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
8

I have a strong suspicion, nay, conviction, that there is something horribly wrong with your program design that it requires you to do this. In Python, unlike Java, very few problems require classes to solve. If there's a function you need, simply define it:

def function_i_need(a):
     """parameter a: an instance of A"""
     pass # do something with 'a'

However, if I cannot dissuade you from making your function a method of the class, you can change an instance's class by setting its __class__ attribute:

>>> class A(object):
...     def __init__(self):
...         pass
... 
>>> class B(A):
...     def functionIneed(self):
...         print 'functionIneed'
... 
>>> a = A()
>>> a.functionIneed()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'functionIneed'
>>> a.__class__ = B
>>> a.functionIneed()
functionIneed

This will work as long as B has no __init__ method, since, obviously, that __init__ will never be called.

A. Jesse Jiryu Davis
  • 23,641
  • 4
  • 57
  • 70
  • 3
    I just blogged about an alternative solution that might be better, or might be far, far worse. Messing with `__class__` is weird and possibly dangerous, but it seems to work (in CPython at least) -- see [A Python "Cast Constructor"](http://late.am/post/2012/04/05/a-python-cast-constructor) – dcrosta Apr 05 '12 at 14:52
  • 3
    @dcrosta Would you mind turning that post into an answer? You know, linkrot etc – Tobias Kienzler Apr 09 '13 at 15:11
  • So if I want to inherit from another class, and want the ability to convert the parent class to the child, is this right? Or am I in the wrong paradigm. `class B(A): def __init__(self, a_instance): a_instance.__class__ = B` – Tahlor Jun 29 '18 at 18:52
5

You said you want to implement something like this:

class B(A):
    def functionIneed():
        pass

But really what you would be making is something more like this (unless you had intended on making a class or static method in the first place):

class B(A):
    def functionIneed(self):
        pass

Then you can call B.functionIneed(instance_of_A). (This is one of the advantages of having to pass self explicitly to methods.)

wkschwartz
  • 3,817
  • 2
  • 29
  • 33
0

You did not correctly define your classes. Should be like this:

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

class B(A):
    def __init__(self):
        super(B,self).__init__()

    def functionIneed(self):
        pass

Then you can

j=B()
j.fuctionIneed()

as expected

You forgot to refer to the ins

John Moore
  • 162
  • 1
  • 6
  • OP has an existing obj from parent class that needs to have the child function `functionIneed()`, not a brand new obj from child class. – Wtower Feb 04 '22 at 12:46
0

Just thinking outside the box:

Instead of a new class with the function you want, how about just adding the function to the class or instance you already have?

There is a good description of this in Adding a Method to an Existing Object Instance

Ben Law
  • 58
  • 6
0

This comment shares a link, I copy-pasted the contents here in case of link-rot. Please consider visiting the original link if possible.

import copy

class Base(object):
    def __init__(self):
        self.base_init = True

    def foo(self):
        return 'base foo'

    def bar(self):
        return 'base bar'

class Child(Base):
    def __new__(cls, other):
        if isinstance(other, Base):
            other = copy.copy(other)
            other.__class__ = Child
            return other
        return object.__new__(cls)

    def __init__(self, other):
        self.child_init = True

    def bar(self):
        return 'child bar'
b = Base()
assert b.base_init == True
assert b.foo() == 'base foo'
assert b.bar() == 'base bar'
assert b.__class__ == Base

c = Child(b)
assert c.base_init == True
assert c.child_init == True
assert c.foo() == 'base foo'
assert c.bar() == 'child bar'
assert c.__class__ == Child
assert b.__class__ == Base
charelf
  • 3,103
  • 4
  • 29
  • 51
-1

How about:

i = module.getObject() # i will get object that is class A
try:
    i.functionIneed()
except AttributeError:
    # handle case when u have a bad object

Read up on duck typing.

sureshvv
  • 4,234
  • 1
  • 26
  • 32