Вызывать метод родительского класса из дочернего класса в Python?
-
03-07-2019 - |
Вопрос
При создании простой иерархии объектов в Python я хотел бы иметь возможность вызывать методы родительского класса из производного класса.В Perl и Java для этого есть ключевое слово (super
).В Perl я мог бы сделать это:
package Foo;
sub frotz {
return "Bamf";
}
package Bar;
@ISA = qw(Foo);
sub frotz {
my $str = SUPER::frotz();
return uc($str);
}
В python кажется, что я должен явно назвать родительский класс из дочернего.В приведенном выше примере мне нужно было бы сделать что-то вроде Foo::frotz()
.
Это кажется неправильным, поскольку такое поведение затрудняет создание глубоких иерархий.Если дочерним элементам нужно знать, какой класс определил унаследованный метод, то создаются всевозможные информационные проблемы.
Является ли это фактическим ограничением в python, пробелом в моем понимании или и тем, и другим?
Решение
Да, но только с занятия в новом стиле.Используйте super()
функция:
class Foo(Bar):
def baz(self, arg):
return super(Foo, self).baz(arg)
Для Python 3.x вы можете использовать:
class Foo(Bar):
def baz(self, arg):
return super().baz(arg)
Другие советы
Python также имеет супер также:
супер(type[, object-or-type])
Возвращает прокси-объект, который делегирует вызовы методов родительскому или родственному классу типа.Это полезно для доступа к унаследованным методам, которые были переопределены в классе.Порядок поиска такой же, как и в getattr(), за исключением того, что сам тип пропущен.
Пример:
class A(object): # deriving from 'object' declares A as a 'new-style-class'
def foo(self):
print "foo"
class B(A):
def foo(self):
super(B, self).foo() # calls 'A.foo()'
myB = B()
myB.foo()
ImmediateParentClass.frotz(self)
будет просто отлично, независимо от того, определен ли непосредственный родительский класс frotz
сам или унаследовал это. super
необходим только для надлежащей поддержки множественный наследование (и тогда оно работает только в том случае, если каждый класс использует его должным образом).В целом, AnyClass.whatever
собирается посмотреть вверх whatever
в AnyClass
предки, если AnyClass
не определяет / переопределяет его, и это справедливо для "дочернего класса, вызывающего родительский метод", как и для любого другого случая!
Python 3 имеет другой и более простой синтаксис для вызова родительского метода.
Если Foo
класс наследуется от Bar
, затем из Bar.__init__
может быть вызван из Foo
через super().__init__()
:
class Foo(Bar):
def __init__(self, *args, **kwargs):
# invoke Bar.__init__
super().__init__(*args, **kwargs)
Во многих ответах объяснялось, как вызвать метод из родительского, который был переопределен в дочернем.
Однако
"как вы вызываете метод родительского класса из дочернего класса?"
также может просто означать:
"как вы называете унаследованные методы?"
Вы можете вызывать методы, унаследованные от родительского класса, так же, как если бы они были методами дочернего класса, при условии, что они не были перезаписаны.
например ,в python 3:
class A():
def bar(self, string):
print("Hi, I'm bar, inherited from A"+string)
class B(A):
def baz(self):
self.bar(" - called by baz in B")
B().baz() # prints out "Hi, I'm bar, inherited from A - called by baz in B"
да, это может быть довольно очевидно, но я чувствую, что, не указывая на это, у людей может сложиться впечатление, что вам приходится перепрыгивать через нелепые препятствия только для того, чтобы получить доступ к унаследованным методам в python.Тем более, что этот вопрос высоко ценится при поиске "как получить доступ к методу родительского класса в Python", а OP написан с точки зрения новичка в python.
Я нашел:https://docs.python.org/3/tutorial/classes.html#inheritance чтобы быть полезным для понимания того, как вы получаете доступ к унаследованным методам.
Вот пример использования супер():
#New-style classes inherit from object, or from another new-style class
class Dog(object):
name = ''
moves = []
def __init__(self, name):
self.name = name
def moves_setup(self):
self.moves.append('walk')
self.moves.append('run')
def get_moves(self):
return self.moves
class Superdog(Dog):
#Let's try to append new fly ability to our Superdog
def moves_setup(self):
#Set default moves by calling method of parent class
super(Superdog, self).moves_setup()
self.moves.append('fly')
dog = Superdog('Freddy')
print dog.name # Freddy
dog.moves_setup()
print dog.get_moves() # ['walk', 'run', 'fly'].
#As you can see our Superdog has all moves defined in the base Dog class
В Python тоже есть функция super().Это немного неудобно из-за классов старого и нового стилей Python, но довольно часто используется, напримерв конструкторах:
class Foo(Bar):
def __init__(self):
super(Foo, self).__init__()
self.baz = 5
Я бы рекомендовал использовать CLASS.__bases__
что - то вроде этого
class A:
def __init__(self):
print "I am Class %s"%self.__class__.__name__
for parentClass in self.__class__.__bases__:
print " I am inherited from:",parentClass.__name__
#parentClass.foo(self) <- call parents function with self as first param
class B(A):pass
class C(B):pass
a,b,c = A(),B(),C()
Если вы не знаете, сколько аргументов вы можете получить, и хотите передать их все также ребенку:
class Foo(bar)
def baz(self, arg, *args, **kwargs):
# ... Do your thing
return super(Foo, self).baz(arg, *args, **kwargs)
В python также есть функция super().
Пример того, как метод суперкласса вызывается из метода подкласса
class Dog(object):
name = ''
moves = []
def __init__(self, name):
self.name = name
def moves_setup(self,x):
self.moves.append('walk')
self.moves.append('run')
self.moves.append(x)
def get_moves(self):
return self.moves
class Superdog(Dog):
#Let's try to append new fly ability to our Superdog
def moves_setup(self):
#Set default moves by calling method of parent class
super().moves_setup("hello world")
self.moves.append('fly')
dog = Superdog('Freddy')
print (dog.name)
dog.moves_setup()
print (dog.get_moves())
Этот пример похож на описанный выше.Однако есть одно отличие, что super не передает ему никаких аргументов.Приведенный выше код выполняется в версии python 3.4.
В Python 2 мне не очень повезло с super().Я использовал ответ из jimifiki в этой теме SO как ссылаться на родительский метод в python?.Затем я добавил к нему свой собственный небольшой поворот, который, на мой взгляд, является улучшением удобства использования (особенно если у вас длинные имена классов).
Определите базовый класс в одном модуле:
# myA.py
class A():
def foo( self ):
print "foo"
Затем импортируйте класс в другие модули as parent
:
# myB.py
from myA import A as parent
class B( parent ):
def foo( self ):
parent.foo( self ) # calls 'A.foo()'
в этом примере cafec_param является базовым классом (родительский класс), а abc - дочерним классом.abc вызывает метод AWC в базовом классе.
class cafec_param:
def __init__(self,precip,pe,awc,nmonths):
self.precip = precip
self.pe = pe
self.awc = awc
self.nmonths = nmonths
def AWC(self):
if self.awc<254:
Ss = self.awc
Su = 0
self.Ss=Ss
else:
Ss = 254; Su = self.awc-254
self.Ss=Ss + Su
AWC = Ss + Su
return self.Ss
def test(self):
return self.Ss
#return self.Ss*4
class abc(cafec_param):
def rr(self):
return self.AWC()
ee=cafec_param('re',34,56,2)
dd=abc('re',34,56,2)
print(dd.rr())
print(ee.AWC())
print(ee.test())
Выходной сигнал
56
56
56
class department:
campus_name="attock"
def printer(self):
print(self.campus_name)
class CS_dept(department):
def overr_CS(self):
department.printer(self)
print("i am child class1")
c=CS_dept()
c.overr_CS()
class a(object):
def my_hello(self):
print "hello ravi"
class b(a):
def my_hello(self):
super(b,self).my_hello()
print "hi"
obj = b()
obj.my_hello()
Это более абстрактный метод:
super(self.__class__,self).baz(arg)