Skip to content
Advertisement

Multiple Python Inheritance with abstract class calls __new__ method wrong number of arguments

I have the following situation:

class AbstractSpeaker(ABC):
    @abstractmethod
    def say_hello(self)->None:
         pass

    """... other abstract and maybe even concrete methods ..."""

class BasicGreeter:
  """implements a basic say_hello method so that Speakers
  don't need to implement it"""
  def __new__(cls):
      r=object.__new__(cls)
      r._language=Language.English #assume that Language is an appropriate Enum
      return r

 @property
 def language(self)->Language: 
    return self._language

 @language.setter
 def language(self, newLanguage:Language):
    self._language=newLanguage

 def say_hello(self)->None:
    if self.language is Language.English:
       print("Hello")
    elif self.language is Language.German:
       print("Hallo")
    elif self.language is Language.Italian:
      print("Ciao")
    else:
      print("Hi")

class Person(BasicGreeter, AbstractSpeaker):
    def __init__(self, name):
       self.name=name
    """goes on to implement everything AbstractSpeaker speaker commands but should
       use the say_hello method from BasicGreeter, who should also hold the language
       information.
    """

But when I want to generate a new Person I get an TypeError:

>>> peter=Person('Peter')
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
peter=Person('Peter')
TypeError: __new__() takes 1 positional argument but 2 were given

Now I get that it has something to do with the fact that I have implemented a new method in BasicGreeter because when I rewrite BasicGreeter to use an init method instead of the new-method and then explicitly call super.init() in the Person’s init it works. But I wanted to know if there is any way to do this with the new method as having to invoke super.init() in every Speakers init can be a bug source if ever forgotten. Any ideas, can this (a class implementing basic compliance in some areas for an abstract class so that children of that abstract class don’t need to implement the same code) be done? I know that I could always go the 3 generation route making the BasicGreeter an abstract class, but I think that is more elegant way as it allows BasicGreeter to be used for other families f.e. I might have a class Robot with a subclass FriendlyRobot that could also make use of inheriting from BasicGreeter but a Robot is not necessarily a speaker and vice versa.

Advertisement

Answer

The error gives you the solution, simply let the new method to take the arguments even if you don’t use them:

from abc import ABC, abstractmethod

class Language():
    English = 'english'

class AbstractSpeaker(ABC):
    @abstractmethod
    def say_hello(self)->None:
         pass

    """... other abstract and maybe even concrete methods ..."""

class BasicGreeter:
    """implements a basic say_hello method so that Speakers don't need to implement it"""
    def __new__(cls, *args, **kwargs):   # Fix to your code
        # print(args,kwargs)
        r=object.__new__(cls)
        r._language=Language.English 
        return r
    @property
    def language(self)->Language: 
        return self._language

    @language.setter
    def language(self, newLanguage:Language):
        self._language=newLanguage

    def say_hello(self)->None:
        if self.language is Language.English:
            print("Hello")
        elif self.language is Language.German:
            print("Hallo")
        elif self.language is Language.Italian:
            print("Ciao")
        else:
            print("Hi")

class Person(BasicGreeter, AbstractSpeaker):
    def __init__(self, name):
        self.name=name
        
    """goes on to implement everything AbstractSpeaker speaker commands but should
       use the say_hello method from BasicGreeter, who should also hold the language
       information.
    """

This piece of code works, said that, I’m not sure in what you need such a structure inside new, is a way of making a singleton?

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement