2010-09-20 1 views
4

Мое множественное наследство-фу не сильно. Я пытаюсь создать суперкласс, у которого __init__ принимает необязательный именованный параметр и подклассы его, которые также наследуются от встроенных типов. К сожалению, у меня появляются, не имеют ни малейшего представления о том, как сделать эту работу:Добавление необязательных параметров в конструкторы многопоследовательных подклассов встроенных типов?

>>> class Super(object): 
    name = None 
    def __init__(self, *args, name=None, **kwargs): 
     self.name = name 
     super().__init__(self, *args, **kwargs) 

>>> class Sub(Super, int): 
    pass 

>>> Sub(5) 
5 

>>> Sub(5, name="Foo") 
Traceback (most recent call last): 
    File "<pyshell#10>", line 1, in <module> 
    Sub(5, name="Foo") 
TypeError: 'name' is an invalid keyword argument for this function 

(. Я также попробовал без super() вызова, но результат был тот же)

Возможно, кто-то с лучшим знанием множественного наследования может указывать на меня в правильном направлении?

Update:

Вот решение, которое я закончил с, на основе Alex's answer.

Это еще немного Hacky (по changining __new__ «подпись s частично за счет строительства), но он будет работать до тех пор, как появляется суперкласс в подклассы» ТОиР до встроенного типа и определение __new__ таким образом, позволяет мне создавать подклассы, которые работают с разными встроенными типами, без добавления отдельного __new__ к каждому из них.

>>> class Super(object): 
    name = None 
    def __new__(cls, *args, name=None, **kwargs): 
     inner = super().__new__(cls, *args, **kwargs) 
     inner.name = name 
     return inner 

>>> class Sub(Super, int): 
    pass 

>>> Sub(5) 
5 

>>> Sub(5, name="Foo") 
5 

>>> _.name 
'Foo' 
+0

Какова цель класса 'name = None'? если вы хотите, чтобы он был там, его, вероятно, можно было бы назвать чем-то отличным от 'self.name' – msw

+0

' __init__' здесь урезано от того, которое я использую в реальном классе, для демонстрации. Настоящий не обязательно устанавливает 'self.name' каждый раз и установка' name = None' в суперклассе предоставляет значение по умолчанию. –

ответ

3

Вы просто не можете передавать произвольные параметры (будь то позиционные или именованные единицы) в столь же произвольно суперкласса (т.е. «непосредственно предшествующего типа в mro из независимо от текущего типа лист») - большинство типов и классов просто не принимают произвольные параметры, отличные по причинам тоже - цитируя из середины Zen of Python,

Errors should never pass silently. 
Unless explicitly silenced. 

и в большинстве случаев вызова (например) int(name='booga')бы быть, конечно, ошибка.

Если вы хотите, чтобы вы были странно названы class Super, чтобы иметь возможность «передавать» произвольные параметры, вы также должны убедиться, что все классы когда-либо использовались в качестве баз после того, как он может справиться с этим - так, например, можно назвать int с одним параметром (или ровно два: строки и основания), поэтому, если это абсолютно необходимо для вас, что class Subможет многократно наследовать от понижающего обходя Superи межд, у вас есть на поле, что, например:

class Int(int): 
    def __new__(cls, *a, **k): 
     return int.__new__(Int, a[0] if a else 0) 

Обратите внимание, что вы должны переопределить __new__, не__init__ (он не делает никакого вреда, если вы также переопределения последнего, но это не имеет значения так или иначе): int неизменна, так что значение должно быть установлено на __new__ время.

Теперь, такие вещи, как

>>> class X(Super, Int): pass 
... 
>>> X(23, za='zo') 
23 
>>> 

работы. Но обратите внимание, что X должен подкласс от Int (нашего __new__ -sanitizing версии int), не из int себя, что, совершенно правильно, имеет неумолимый __new__!-)

+0

(Имена только для примера, конечно!) Спасибо за помощь; Я предполагал, что «__init__» «потребляет» дополнительный параметр, прежде чем он когда-либо был замечен «int» (что в ретроспективе было глупо от меня). –