У меня следующая ситуация:
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.
"""
Но когда я хочу создать нового человека, я получаю 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
Теперь я понимаю, что это как-то связано с тем фактом, что я реализовал метод новый в BasicGreeter, потому что, когда я переписываю BasicGreeter, чтобы использовать метод в этом вместо метода новый, а затем явно вызывать super.в этом() в инициализации Person оно работает. Но я хотел знать, есть ли способ сделать это с помощью метода новый, поскольку необходимость вызывать super.в этом() в каждой инициализации динамиков может быть источником ошибки, если ее когда-либо забудут. Любые идеи, можно ли это (класс, реализующий базовое соответствие в некоторых областях для абстрактного класса, чтобы дочерним элементам этого абстрактного класса не нужно было реализовывать один и тот же код)? Я знаю, что всегда мог бы пойти по пути 3-го поколения, сделав BasicGreeter абстрактным классом, но я думаю, что это более элегантный способ, поскольку он позволяет использовать BasicGreeter для других семейств, например. У меня может быть класс Robot с подклассом FriendlyRobot, который также может использовать наследование от BasicGreeter, но робот не обязательно является говорящим, и наоборот.
При использовании super необходимо сохранить подпись переопределенных методов совместимый с тем, что они переопределяют. Если ваш класс добавляет является параметром, он должен гарантировать, что аргумент будет передан в super, потому что предок некоторый этого не ожидает.
@Tomerikoo, поскольку в этом нужно вызывать дополнительно, новый вызывается автоматически.
Но вызов super внутри __init__ — это стандартный идиоматический способ наследования. Использование __new__ только для того, чтобы обойти это, является однозначным. Что плохого в том, чтобы вызвать super? В любом случае, ошибка довольно очевидна: ваш __new__ принимает только класс, но вы передаете ему дополнительные аргументы.
В этом случае я хотел бы избежать этого в Person, поскольку BasicGreeter не является основным предком Person, а скорее родственником на расстоянии, который оставил полезное наследие, в данном случае функцию say_hello и свойство языка. Но хорошо, я изменил новый метод BasicGreeter, чтобы использовать аргумент * args и супер вместо объекта, и теперь он работает нормально.






Ошибка дает вам решение, просто позвольте методу новый принимать аргументы, даже если вы их не используете:
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.
"""
Этот кусок кода работает, сказал что, я не уверен в том, что вам нужна такая структура внутри новый, это способ сделать синглтон?
Нет, это просто шаблон, который появился в моем проекте. Я работаю, я просто не понял, что все параметры инициализации будут переданы новому методу родителя. Есть ли способ избежать этого, кроме явного супервызова?
Не используйте object; используйте super. Если BasicGreeter появляется непосредственно перед object в MRO, он делает то же самое. Если он делает нет, то object.__new__ вызывается преждевременно, а поскольку object.__new__ не использует super, никакой другой метод __new__ класса вызываться не может.
Да, это технически возможно, вы можете использовать метакласс (предпочтительно) или даже, возможно, декоратор класса, в любом случае, обычно вызов «супер» был бы правильным способом здесь.
Этого не должно быть в
__new__. Я действительно не мог понять, почему вы не используете__init__...