Вызов переопределенного метода, суперкласс переадресовывает вызовы
Этот код генерирует исключение: 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.)