2

Here is my code. Which is an exmaple of multiple inheritances in pyton. But it shows an error. I want to create a program where single inheritance and multiple inheritance will be used. To do this, create a base class Employee. And from Employee create two classes Programmer and Manager. Now using multiple inheritance create a class DevManager which inheritate from Programmer and Manager. But when I wnat to create an object of DevManager class with proper parameter it will show an error. Below is my code, I can't find where is the error.

class Employee:
    def __init__(self, id, ename):
        self.id = id
        self.ename = ename

    def showInfo(self):
        print("ID=", self.id, "Name of employee=", self.ename)

class Programmer(Employee):
    def __init__(self, id, ename, language):
        super().__init__(id, ename)
        self.language = language

    def showInfo(self):
        super().showInfo()
        print("Development Language=", self.language)

class Manager(Employee):
    def __init__(self, id, ename, department):
        super().__init__(id, ename)
        self.department = department

    def showInfo(self):
        super().showInfo()
        print("Department=", self.department)

# Define Development Manager class using Multiple inheritances
class DevManager(Programmer, Manager):
    def __init__(self, id, ename, language, department):
        Programmer.__init__(self, id, ename, language)
        Manager.__init__(self, id, ename, department)

    def showInfo(self):
        super().showInfo()

# Main
obj = DevManager("A101", "Rajib Menon", "Python", "Engineering")
obj.showInfo()

In this program it will not create an object of Programmer class. Following error shows to me.

Traceback (most recent call last):

  File "C:\Users\Home\.spyder-py3\multiple.py", line 41, in <module>
    obj = DevManager("A101", "Rajib Menon", "Python", "Engineering")

  File "C:\Users\Home\.spyder-py3\multiple.py", line 33, in __init__
    Programmer.__init__(self, id, ename, language)

  File "C:\Users\Home\.spyder-py3\multiple.py", line 13, in __init__
    super().__init__(id, ename)

TypeError: __init__() missing 1 required positional argument: 'department'
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • 2
    Why are you calling `Programmer.__init__` instead of just `super().__init__` as the other classes do? – John Gordon Aug 20 '23 at 15:39
  • Does this answer your question? [Multiple Inheritance in Python - TypeError "missing 1 required positional argument"](/q/72034905/4518341) – wjandrea Aug 20 '23 at 15:50
  • BTW, welcome back to Stack Overflow! Check out the [tour] and [ask] for tips like how to write a good title. I put a new title here, but it could still be better. – wjandrea Aug 20 '23 at 15:58
  • *"it will not create an object of Programmer class"* -- That's not quite what's happening; you're not actually creating a `Programmer` object anywhere; the error is occurring when creating a `DevManager` object and it runs `Programmer.__init__`. I imagine you know this already, just didn't phrase it properly. – wjandrea Aug 20 '23 at 16:03

3 Answers3

1

the problem was because the way of super() function works what it does is : it calls the method from the next class in MRO (method resolution order).

the mro in this case is :

print(DevManager.mro())
[<class '__main__.DevManager'>, <class '__main__.Programmer'>, <class '__main__.Manager'>, <class '__main__.Employee'>, <class 'object'>]

what happens when you instantiate is the first super() function will run the first __init__() function of the first class in the mro list Programmer then the second super() function will run the __init__() function of Manager and so on and you need to give the __init__() function its right data and you don't know what is the order of running multiple super() function so you need to add *args , **kwargs to each one and it will do its work

class Employee:
        def __init__(self, id, ename):
                self.id = id
                self.ename = ename
                super().__init__()

        def showInfo(self):
                print("ID=", self.id, "Name of employee=", self.ename)

class Programmer(Employee):
        def __init__(self, id, ename, language , *args, **kwargs):
                print("Set Programmer attrs")
                self.language = language
                super().__init__(id, ename,*args,**kwargs)

        def showInfo(self):
                super().showInfo()
                print("Development Language=", self.language)

class Manager(Employee):
        def __init__(self, id, ename, department,*args, **kwargs):
                print("Set Manager attrs")
                self.department = department
                super().__init__(id, ename,*args,**kwargs)

        def showInfo(self):
                super().showInfo()
                print("Department=", self.department)

# Define Development Manager class using Multiple inheritances
class DevManager(Programmer, Manager):

        def __init__(self, *args , **kwargs):
            super().__init__( *args , **kwargs)

        def showInfo(self):
                super().showInfo()

# Main
print(DevManager.mro())
obj = DevManager("A101", "Rajib Menon", "Python", "Engineering")
obj.showInfo()



another Solution

you can call __init__() from each Class to avoid the arguments problem

class Employee:
    def __init__(self, id, ename):
        self.id = id
        self.ename = ename

    def showInfo(self):
        print("ID=", self.id, "Name of employee=", self.ename)

class Programmer(Employee):
    def __init__(self, id, ename, language):
        Employee.__init__(self,id, ename)
        self.language = language

    def showInfo(self):
        super().showInfo()
        print("Development Language=", self.language)

class Manager(Employee):
    def __init__(self, id, ename, department):
        Employee.__init__(self,id, ename)
        self.department = department

    def showInfo(self):
        super().showInfo()
        print("Department=", self.department)

# Define Development Manager class using Multiple inheritances
class DevManager(Programmer, Manager):
    def __init__(self, id, ename, language, department):
        
        Programmer.__init__(self, id, ename, language)
        Manager.__init__(self, id, ename, department)

    def showInfo(self):
        super().showInfo()

# Main
obj = DevManager("A101", "Rajib Menon", "Python", "Engineering")
obj.showInfo()

Ayman
  • 363
  • 2
  • 9
0

Use named paramaters not positional at object creation.

class Employee:
    def __init__(self, id, ename, **kwargs):
        self.id = id
        self.ename = ename


class Programmer(Employee):
    def __init__(self, language, **kwargs):
        super().__init__(**kwargs)
        self.language = language


class Manager(Employee):
    def __init__(self, department, **kwargs):
        super().__init__(**kwargs)
        self.department = department


class DevManager(Programmer, Manager):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

Can Instantiate Any Class More Clearly.

# Main
obj = DevManager(id="A101",
                 ename="Rajib Menon",
                 language="Python",
                 department="Engineering")
obj_p = Programmer(id="A102",
                   ename="Monty",
                   language="Python")
-1
class Employee:
    def __init__(self, id, ename):
        self.id = id
        self.ename = ename

    def showInfo(self):
        print("ID=", self.id, "Name of employee=", self.ename)

class Programmer(Employee):
    def __init__(self, id, ename, language):
        super().__init__(id, ename)
        self.language = language

    def showInfo(self):
        super().showInfo()
        print("Development Language=", self.language)

class Manager(Employee):
    def __init__(self, id, ename, department):
        super().__init__(id, ename)
        self.department = department

    def showInfo(self):
        super().showInfo()
        print("Department=", self.department)

class DevManager:
    def __init__(self, id, ename, language, department):
        self.programmer = Programmer(id, ename, language)
        self.manager = Manager(id, ename, department)

    def showInfo(self):
        self.programmer.showInfo()
        self.manager.showInfo()

# Main
obj = DevManager("A101", "Rajib Menon", "Python", "Engineering")
obj.showInfo()

In this modified example, the DevManager class uses composition by creating instances of the Programmer and Manager classes. This approach avoids the complexity of multiple inheritance and the diamond problem ( that result a logical issue with the method resolution order (MRO)).

Print:

ID= A101 Name of employee= Rajib Menon
Development Language= Python
ID= A101 Name of employee= Rajib Menon
Department= Engineering
AkramLok
  • 36
  • 6
  • But then a `DevManager` isn't an `Employee` or a `Programmer` or a `Manager`, so what's the point? Don't get me wrong, composition over inheritance is a great rule of thumb, but this doesn't seem like a good use of it. This structure means that a `DevManager` **has** a `Programmer` and a `Manager` (maybe working under them, conceptually), instead of **being** a `Programmer` and a `Manager` (which is the actual conceptual structure you want). – wjandrea Aug 20 '23 at 16:11
  • Thanks for the clarification @wjandrea, i did give the answer with the composition method to just avoid errors that may occurs later, when multiple inheritance in diamond like ambiguity in `method resolution`, `attribute and method name clashes` (if they have the same names), `inconsistent state`..., those can lead to unexpected behavior. – AkramLok Aug 20 '23 at 16:53