2016-07-04 1 views
0

У меня есть ситуация, когда метод базового класса (метод __init__ на Python) выполняет большую работу. Производные классы переопределяют __init__, чтобы просто установить переменную объекта, а затем делегировать базовому классу __init__. Это прекрасно работает, но теперь у меня есть ситуация.Методы базового класса, которые будут использоваться всеми производными классами, кроме одного

У меня есть некоторый код, который прекрасно вписывается в базовом классе __init__ которой все остальные производные классы кроме один (назовем его A) нужно использовать. Представьте себе, что базовый класс __init__ был чем-то вроде этого.

def __init__(self): 
    Action 1... 
    Action 2... 

Теперь все производные классы просто делегируют непосредственно этому. Однако A должен иметь только Действие 2 в его __init__. Теперь сидение уродливо. Я могу разделить Action 1 и Action 2 на две отдельные функции, и базовый класс просто вызывает Action2. Тогда у большинства классов будет что-то подобное.

def __init__(self): 
    self.Action1() 
    Other init code... 
    super().__init__() 

и для класса A, это будет

def __init__(self): 
    Some init code.... 
    super().__init__() 

Но вы можете видеть, что есть кусок кода (вызов self.Action1 что) я должен повторить в большинстве производных классов. Это плохо. Я не уверен, как правильно это закодировать с минимальным повторяющимся кодом, и вам нужно знать, как это сделать.

+1

типичный ответ _maybe А не дочерний класс really_. Подумайте о том, чтобы положить A в качестве родителя (выше в иерархии, а не ниже). – Aganju

+0

В '' 'A''' вы можете * отменить *' '' Action1''' после вызова '' 'super() .__ init __ () '' '? – wwii

+0

@Aganju A - ребенок. Базовый класс содержит много общего кода. В дочерних классах реализовано несколько методов, которые позволяют им вписаться в большую структуру. –

ответ

3

Ярчайшее решением будет использовать аргумент по умолчанию:

class Base: 
    def __init__(self, *, doAction1=True): 
     if doAction1: 
      Action 1... 
     Action 2... 

Тогда в классе A вы можете иметь:

def __init__(self): 
    Some init code.... 
    super().__init__(doAction1=False) 
+0

Это выглядит хорошо. Я сделал что-то подобное, но вместо аргумента задал атрибут объекта, на который основывался базовый класс. –

+0

Если не поступит другое предложение, я принимаю этот ответ. Похоже, это самый минимальный способ сделать это. –

0
атрибут

класса, которые могут быть перекрыты - аналогичен по умолчанию аргумента в __init__ , (Определение класса Python v2.7).

class Foo(object): 
    action1 = True 
    action2 = True 
    def __init__(self): 
     if self.action1: 
     print('action1') 
     if self.action2: 
     print('action2') 

class Bar(Foo): 
    def __init__(self): 
     super(Bar, self).__init__() 
     print('Bar') 

class Baz(Foo): 
    action2 = False 
    def __init__(self): 
     super(Baz, self).__init__() 
     print('Baz') 
+0

Это работает, но я думаю, что решение @ ecatmur чище. –

+0

@NoufalIbrahim ... Я поддержал решение ecatmur, а затем решил опубликовать это для * контраста *. – wwii

0

При принятии проектных решений часто стоит учитывать, является ли наследование правильным путем. Поразмышляйте над тем, действительно ли вам действительно нужно наследование, или это просто осложнит ситуацию.

Если вы решили, что наследование на самом деле не требуется (текущая проблема, о которой вы спрашиваете, может или не может быть признаком того, что это так), прежде чем прибегать к наследованию, я предлагаю вам изучить решение вашей проблемы используя что-то вроде этого:

def Action1(obj): 
    <do Action 1> 

def Action2(obj): 
    <do Action 2> 

def Action1and2(obj): 
    Action1(obj) 
    Action2(obj) 

class A: 
    def __init__(self): 
     Action2(self) 

class Other: 
    def __init__(self): 
     Action1and2(self) 

Обратите внимание, что для Other объектов, вы по-прежнему только 1 строку кода, и вы вообще избежать наследования.

Если вам нужно было решить, что наследование необходимо, т. Е. Родительские объекты, которые вы создаете, делают больше, чем просто настройка вещей с помощью некоторых действий (они предоставляют дополнительную функциональность или доступ к данным) - вы можете попытаться решить вашу проблему с использованием композиции вместо этого, как это:

class Action1Doer: 
    def __init__(self,obj): 
     <do Action 1> 

class Action2Doer: 
    def __init__(self,obj): 
     <do Action 2> 

class Action1and2Doer: 
    def __init__(self,obj): 
     self.a1 = Action1Doer(obj) 
     self.a2 = Action2Doer(obj) 

class A: 
    def __init__(self): 
     self.thing2 = Action2Doer(self) 

class Other: 
    def __init__(self): 
     self.thing1and2 = Action1and2Doer(self) 

Обратите внимание, что, опять же, у вас есть только одну строку кода в каждом из способов инициализации.Кстати, все дело в этом. iscertainlynothingnew в мире кодирования.

Вы также можете смешать все вместе:

def Action1(obj): 
    <do Action 1> 

class Action2Doer: 
    def __init__(self,obj): 
     <do Action 2> 

class Action1and2Doer: 
    def __init__(self,obj): 
     Action1(obj) 
     self.a2 = Action2Doer(obj) 

class A: 
    def __init__(self): 
     self.thing2 = Action2Doer(self) 

class Other: 
    def __init__(self): 
     self.thing2 = Action1and2Doer(self).a2 
+0

Я предполагаю, что это возможно, но «Action1and2Doer» звучит довольно надуманно. Нет? –

+0

Это, по сути, базовый класс, который вы уже используете, верно? Я просто даю ему описательное имя, чтобы разъяснить объяснение. –

Смежные вопросы

 Смежные вопросы