Python: многоуровневое наследование

У меня проблемы с поиском эффективного решения проблемы наследования Python.

Итак, существует некоторый код вроде следующего:

class Foo( object ):
        def __init__():
                self.some_vars
        def foo_func():
                x = Bar()
        def foo_bar_func()
                x += 1

class Fighters( Foo ):
        def __init__():
                Foo.__init__()
        def func1():
                Foo.some_attribute
        def func2():
                Foo.someother_func()

class Bar():
        def bar_func():
                #some stuff here

Проблема в том, что мне нужно переопределить Bar.bar_func(), но это два уровня глубины. Я решил это, выполнив следующие действия:

class Foo( Foo ):
        def __init__():
                Foo.__init__()
        def foo_func():          #Overridden method
                x = myBar()   

class myFighters( Foo ):
        def __init__():
                Foo.__init__()
        def func1():
                Foo.some_attribute
        def func2():
                Foo.someother_func()

class myBar():
        def bar_func():      #the function that I actually need to change
                #my sweet code here

Единственное, что на самом деле отличается, - это myBar.bar_func(), но мне пришлось сделать как минимум 2 вещи, которые я считаю некрасивыми.

Во-первых, мне пришлось создать class Foo, унаследованный от Foo. Это кажется странным делом, и оно не дает ясности. Я сделал это, чтобы избавить меня от необходимости переименовывать каждую ссылку в myFighters с Foo на myFoo.

Во-вторых, мне нужно скопировать весь код из Fighters в myFighters с единственной целью - использовать замещающую функцию в Bar(). Fighters и myFighters абсолютно одинаковы, за исключением того, что Fighters использует Foo, который вызывает Bar(), а myFighters использует Foo, который вызывает myBar(). Есть ли у кого-нибудь предложения по исправлению этих двух проблем? Или я должен просто быть благодарным, что нашел решение и продолжил свою жизнь ...


person AlENeuman    schedule 18.05.2016    source источник


Ответы (2)


После некоторой очистки кода для создания работоспособного примера:

class Foo( object ):
        def __init__(self):
                print("foo init")
                self.foo_func()
        def foo_func(self):
                print("making bar")
                self.x = Bar()
        def foo_bar_func(self):
                self.x.bar_func()

class Fighters( Foo ):
        def __init__(self):
                print("fighters init")
                Foo.__init__(self)
        def func1(self):
                Foo.some_attribute
        def func2(self):
                Foo.someother_func()

class Bar(object):
        def __init__(self):
                print("bar init")
        def bar_func(self):
                #some stuff here
                print("bar bar_func")

Создайте экземпляр оригинального истребителя:

f1 = Fighters()
f1.foo_bar_func()

и вызывает метод из исходного класса bar:

fighters init
foo init
making bar
bar init
bar bar_func

Теперь мы можем создать подклассы Fighters с помощью MyFighters и Bar с помощью MyBar. Замените foo_func класса Foo на MyFighters с вызовом конструктора MyBar, и он делает то, что вы хотите, без копирования методов:

class MyFighters(Fighters):
        def foo_func(self):
                print("making mybar")
                self.x = MyBar()

class MyBar(Bar):
        def bar_func(self):
                print("mybar bar_func")

Когда мы создаем нового истребителя:

f2 = MyFighters()
f2.foo_bar_func()

мы видим, что он вызывает метод из нового класса bar:

fighters init
foo init
making mybar
bar init
mybar bar_func

Ясно, что это сработало только потому, что метод, который создал объект Bar, было тривиально для подкласса и замены. Как правило, это не так, поскольку это, вероятно, будет выполняться непосредственно в init, а не вызывать метод для этого. Таким образом, дизайн исходных классов позволил запустить этот пример.

person Neapolitan    schedule 18.05.2016

Все методы, определенные в классе, принимают экземпляр в качестве первого аргумента. Соглашение заключается в том, чтобы вызвать экземпляр self и ссылаться на него как на таковой:

class Foo(object):
    def __init__(self):
        self.x = 1

Во-вторых, если вам не нужно перезаписывать метод родительского класса, просто оставьте его:

class Fighters(Foo):
    # __init__ would be here, but I leave it out to inherit the method

    def func_1(self):
        ...

Наконец, если вы хотите сослаться на поведение родителей, используйте super():

class MyFighters(Fighters):
    def __init__(self):
         super(MyFighters, self).__init__()
         self.y = 2

См. Также этот пример и официальные документы Python по classes.

person Razzi Abuissa    schedule 18.05.2016