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?