'How to use the second parent class methods which is inheriting from an interface in python?

I am trying to implement an interface and this interface is taken by two concrete classes say class First and class Second, I have another class that takes these two classes as a parent class CO. The class CO makes a decision based on a flag to return which of the two inherited classes, so as to use their implementation.

from abc import ABC, abstractmethod

class common(ABC):
    @abstractmethod
    def firstfunction(self):
        pass 

    @abstractmethod
    def secondfunction(self):
        pass

class First(common):
    def __init__(self)-> boto3:
        self.ert = "danish"
        # self.username = kwargs["username"]
        # self.password = kwargs["password"]

        print("Inside First function")

    def firstfunction(self):
        print("My implementation of the first function in FIRST CLASS")

    def secondfunction(self):
        print("My implementation of the second function in FIRST CLASS")   

class Second(common):
    def __init__(self):
        self.rty = "pop"
        # self.session_id = kwargs["session_id"]

        print("Inside Second function")

    def firstfunction(self):
        print("My implementation of the first function in SECOND CLASS")

    def secondfunction(self):
        print("My implementation of the second function in SECOND CLASS")

class CO(First, Second):
    def __init__(self):
        self.inst = self.jo()

    def jo(self):
        a = True 

        if a:
            main_object = First()
            return main_object
        else:
            main_object = Second()

I am instantiating and calling the methods

mymainclass = co()
objt = mymainclass

objt.firstfunction()
objt.secondfunction()

So my condition is if the flag a = True in the CO class then the Concrete class First implementation of the methods should be used and we should get the output like this:

Inside the First function

My implementation of the first function in FIRST CLASS

My implementation of the second function in FIRST CLASS

If the flag a = False in the CO class then concrete class Second should be used and we should get the output like this:

Inside the Second function

My implementation of the first function in FIRST CLASS

My implementation of the second function in FIRST CLASS

From the given code I am getting the following output for the flag a = False :

Inside the Second function

My implementation of the first function in FIRST CLASS

My implementation of the second function in FIRST CLASS

Can someone make this code work? What am I doing wrong? I know I can make a function that takes these two classes as variables and then return what I want based on a condition. But I want to use classes for the same



Solution 1:[1]

I would not inherit class CO from either First or Second because you want to end up with an object that is either an instance of class First or class Second. The most straightforward way of doing this is to define method __new__ which will give you more control over instance creation.

Keep all of your code the same (after fixing the obvious errors, such as boto3 not being defined) and changing class CO as follows:


class CO:
    def __new__(cls):
        a = True

        if a:
            main_object = First()
        else:
            main_object = Second()
        return main_object

o = CO()
print(type(o))

Prints:

Inside First function
<class '__main__.First'>

If you want to better parameterize the instance creation (and simplify the code within __new__), then have variable a be an argument to CO:

class CO:
    def __new__(cls, a):
        return First() if a else Second()

o = CO(False)
print(type(o))

Prints:

Inside Second function
<class '__main__.Second'>

You could optionally have class CO have common as its base class to document that instantiating this class results in an instance that implements the common interface. But doing so will not result in enforcing the actual type that is returned by __new__:

class CO(common):
    def __new__(cls, a) -> common:
        # The Python interpreter is not type-checking what is returned:
        #return First() if a else Second()
        return []

o = CO(False)
print(type(o))

Prints:

<class 'list'>

You can also substitute a factory function for class CO:

def common_factory(a):
    return First() if a else Second()

o = common_factory(False)

Note

If you want to ensure that classes that inherit from base class common must override both firstfunction and secondfunction to more closely emulate a pure interface as implemented in other object-oriented languages, then you should define these functions in common so that they raise an NotImplementedError exception:

class common(ABC):
    @abstractmethod
    def firstfunction(self):
        raise NotImplementedError

    @abstractmethod
    def secondfunction(self):
        raise NotImplementedError

Unfortunately, the enforcement is done at run time with its attendant surprises instead of at compile time as is done in other object-oriented languages.

Solution 2:[2]

Okay I think in this situation, CO class must come from common class and implement the first and second function. In the implementation, it will use the First or Second classes functions depends on the result of jo function. Here is the correct Co class code:

class CO(common):

    def __init__(self):
        self.inst = self.jo()

    def jo(self):
        a = False

        if a:
            return First()

        return Second()

    def firstfunction(self):
        self.inst.firstfunction()

    def secondfunction(self):
        self.inst.secondfunction()


a = CO()
a.firstfunction()
a.secondfunction()

Solution 3:[3]

You can directly call the method you want by using the class name.

Unless you have some pressing reason to do this that you didn't include in your question, I would avoid this in favor of a factory function that returns either a First or Second instance depending on the inputs.

class common(ABC):
    @abstractmethod
    def firstfunction(self):
        pass 

    @abstractmethod
    def secondfunction(self):
        pass

class First(common):
    def __init__(self):
        self.ert = "danish"
        super().__init__(self)
    def firstfunction(self):
        print("My implementation of the first function in FIRST CLASS")

    def secondfunction(self):
        print("My implementation of the second function in FIRST CLASS")   

class Second(common):
    def __init__(self):
        self.rty = "pop"
        super().__init__(self)
    def firstfunction(self):
        print("My implementation of the first function in SECOND CLASS")

    def secondfunction(self):
        print("My implementation of the second function in SECOND CLASS")

class CO(First, Second):
    def __init__(self):
        super().__init__(self)
    def use_first(self):
        return True or False  # whatever logic you have for determining this
    def firstfunction(self):
        if self.use_first():
            return First.firstfunction(self)
        else:
            return First.firstfunction(self)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Muhammet Nusret Özate?
Solution 3 Patrick Haugh