Вызов переопределенного метода, суперкласс переадресовывает вызовы

Этот код генерирует исключение: AttributeError, "wtf!", потому что A.foo() вызывает B.foo1(), не следует ли ему называть A.foo1()? Как заставить его вызывать A.foo1() (и любой вызов метода внутри A.foo() должен вызывать A.*)

class A(object):
    def foo(self):
        print self.foo1()

    def foo1(self):
        return "foo"

class B(A):
    def foo1(self):
        raise AttributeError, "wtf!"

    def foo(self):
        raise AttributeError, "wtf!"

    def foo2(self):
        super(B, self).foo()

myB = B()
myB.foo2()

Ответ 1

В классе A вместо вызова методов self вам необходимо вызвать методы A и передать в self вручную.

Это не обычный способ делать вещи - у вас должна быть действительно хорошая причина для этого.

class A(object):
    def foo(self):
        print A.foo1(self)

    def foo1(self):
        return "foo"

class B(A):
    def foo1(self):
        raise AttributeError, "wtf!"

    def foo(self):
        raise AttributeError, "wtf!"

    def foo2(self):
        super(B, self).foo()

myB = B()
myB.foo2()

Ответ 2

Он работает по назначению, так как работает 100% мировых языков программирования. Подкласс отменяет все методы родительского класса.

Однако, если вы действительно хотите назвать A.foo1(), вы можете сделать это так (я не могу гарантировать). И в любом случае вы не должны этого делать, поскольку это противоречит всем принципам хорошего программирования.

 class A(object):

    def foo(self):
        A.foo1(self)

Ответ 3

В коде:

def foo2(self):
    super(B, self).foo()

self является экземпляром B.

Когда метод, полученный из A, вызывается экземпляром B, он начнет искать в пространстве имен из B, и только если метод не найден (например, не переопределяется B) используется реализация из A, но всегда с само со ссылкой на B. Ни в коем случае само является экземпляром A.

Ответ 4

Можно видеть, что здесь делает Python, но манера переопределения немного экстремальна. Возьмите случай, когда класс A определяет 100 атрибутов, а класс B наследует их и добавляет еще 1 атрибут. Мы хотим, чтобы __init __() для B вызывал __init __() для A и B-код определял только его единственный атрибут. Точно так же, если мы определим метод reset() в A, чтобы установить все атрибуты равными нулю, то соответствующий метод reset() для B должен иметь возможность просто вызвать метод reset() для A, а затем нуль из одного атрибута B вместо дублирования всего кода A. Python затрудняет то, что должно быть основным преимуществом объектно-ориентированного программирования; то есть повторное использование кода. Лучший вариант здесь - избежать переопределения методов, которые мы действительно хотим использовать повторно. Если вы хотите получить представление об осложнениях с Python здесь, попробуйте этот код:

class X(object):
    def __init__ ( self ):
        print "X"
        self.x = 'x'
        self.reset()
        print "back to X"
    def reset ( self ):
        print "reset X"
        self.xx = 'xx'

class Y(X):
    def __init__ ( self ):
        print "Y"
        super(Y,self).__init__()
        self.y = 'y'
        self.reset()
        print "back to Y"
    def reset ( self ):
        print "reset Y"
        super(Y,self).reset()
        print "back to reset Y"
        self.yy = 'yy'

aY = Y()

(Чтобы сделать это правильно, удалите вызов self.reset() в __init __() для класса Y.)