Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

conditional class inheritance in python

I am trying to dynamically create classes in Python and am relatively new to classes and class inheritance. Basically I want my final object to have different types of history depending on different needs. I have a solution but I feel there must be a better way. I dreamed up something like this.

class A:
    def __init__(self):
        self.history={}
    def do_something():
        pass

class B:
    def __init__(self):
        self.history=[]
    def do_something_else():
        pass

class C(A,B):
    def __init__(self, a=False, b=False):
        if a:
            A.__init__(self)
        elif b:
            B.__init__(self)

use1 = C(a=True)
use2 = C(b=True)
like image 734
jamesRH Avatar asked Sep 16 '15 01:09

jamesRH


2 Answers

You probably don't really need that, and this is probably an XY problem, but those happen regularly when you are learning a language. You should be aware that you typically don't need to build huge class hierarchies with Python like you do with some other languages. Python employs "duck typing" -- if a class has the method you want to use, just call it!

Also, by the time __init__ is called, the instance already exists. You can't (easily) change it out for a different instance at that time (though, really, anything is possible).

if you really want to be able to instantiate a class and receive what are essentially instances of completely different objects depending on what you passed to the constructor, the simple, straightforward thing to do is use a function that returns instances of different classes.

However, for completeness, you should know that classes can define a __new__ method, which gets called before __init__. This method can return an instance of the class, or an instance of a completely different class, or whatever the heck it wants. So, for example, you can do this:

class A(object):
    def __init__(self):
        self.history={}
    def do_something(self):
        print("Class A doing something", self.history)

class B(object):
    def __init__(self):
        self.history=[]
    def do_something_else(self):
        print("Class B doing something", self.history)

class C(object):
    def __new__(cls, a=False, b=False):
        if a:
            return A()
        elif b:
            return B()

use1 = C(a=True)
use2 = C(b=True)
use3 = C()

use1.do_something()
use2.do_something_else()

print (use3 is None)

This works with either Python 2 or 3. With 3 it returns:

Class A doing something {}
Class B doing something []
True
like image 61
Patrick Maupin Avatar answered Nov 14 '22 22:11

Patrick Maupin


I'm assuming that for some reason you can't change A and B, and you need the functionality of both.

Maybe what you need are two different classes:

class CAB(A, B): 
    '''uses A's __init__'''

class CBA(B, A):
    '''uses B's __init__'''

use1 = CAB()
use2 = CBA()

The goal is to dynamically create a class.

I don't really recommend dynamically creating a class. You can use a function to do this, and you can easily do things like pickle the instances because they're available in the global namespace of the module:

def make_C(a=False, b=False):
    if a:
        return CAB()
    elif b:
        return CBA()

But if you insist on "dynamically creating the class"

def make_C(a=False, b=False):
    if a:
        return type('C', (A, B), {})()
    elif b:
        return type('C', (B, A), {})()

And usage either way is:

use1 = make_C(a=True)
use2 = make_C(b=True)
like image 45
Russia Must Remove Putin Avatar answered Nov 14 '22 22:11

Russia Must Remove Putin