Многократное наследование Python __new__ и __init__ со строкой и вторым классом
Я пытаюсь создать производный класс, который наследует от str
тип и второй класс. Это проблематично, так как str
тип не просто вызывает __init__
, но __new__
Метод из-за его неизменности. Я знаю что для __init__
и супер, чтобы хорошо работать, вы должны иметь одну и ту же структуру вызова до конца. Однако следующая реализация терпит неудачу:
class base(object):
def __new__(cls, *args, **kwargs):
print "NEW BASE:", cls, args, kwargs
return super(base, cls).__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
print "INIT BASE", args, kwargs
class foo(base, str):
def __new__(cls, *args, **kwargs):
return super(foo, cls).__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
super(foo, self).__init__(*args, **kwargs)
Вот foo('cat')
работает с:
>> NEW BASE: <class '__main__.foo'> ('cat',) {}
>> INIT BASE ('cat',) {}
но с аргументом foo('cat', x=3)
не получается:
>> NEW BASE: <class '__main__.foo'> ('cat',) {'x': 3}
Traceback (most recent call last):
File "inh.py", line 19, in <module>
foo('cat', x=3)
File "inh.py", line 12, in __new__
return super(foo, cls).__new__(cls, *args, **kwargs)
File "inh.py", line 4, in __new__
return super(base, cls).__new__(cls, *args, **kwargs)
TypeError: str() takes at most 1 argument (2 given)
Я могу заставить это работать, изменив base.__new__
метод для:
def __new__(cls, *args, **kwargs):
return super(base, cls).__new__(cls)
но теперь я изменил структуру вызова, что, как мне кажется, позже вызовет у меня проблемы.
Как правильно наследовать от строки и второго класса?
1 ответ
Вы не можете просто сделать
def __new__(cls, *args, **kwargs):
return super(base, cls).__new__(cls)
потому что это вызовет неправильный вызов для новой строки (вы не передадите разрешенный аргумент
>>> foo('t')
NEW BASE: <class '__main__.foo'> ('t',) {}
INIT BASE ('t',) {}
''
Вы должны сделать что-то вроде
def __new__(cls, *args, **kwargs):
return super(base, cls).__new__(cls, *args[:1])
Но это может что-то сломать, если вы будете использовать base
класс как миксин для класса, который __new__
метод принимает более одного аргумента.
как вариант, может быть, вы должны иметь класс, унаследованный от str
но с переопределенным новым методом:
class CarelessStr(str):
def __new__(cls, *args, **kwargs):
return super(CarelessStr, cls).__new__(cls, *args[:1])
class foo(base, CarelessStr):
def __new__(cls, *args, **kwargs):
return super(foo, cls).__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
super(foo, self).__init__(*args, **kwargs)