inheritance:用Python从子类调用父类的方法?

在Python中创建简单对象层次结构时,我希望能够从派生类调用父类的方法。在Perl和Java中,这里有一个关键字(super)。在Perl中,我可能这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
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()函数:

1
2
3
class Foo(Bar):
    def baz(self, arg):
        return super(Foo, self).baz(arg)


Python也有super:

super(type[, object-or-type])

Return a proxy object that delegates method calls to a parent or sibling class of type.
This is useful for accessing inherited methods that have been overridden in a class.
The search order is same as that used by getattr() except that the type itself is skipped.

例子:

1
2
3
4
5
6
7
8
9
10
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()


1
ImmediateParentClass.frotz(self)

无论直接父类定义frotz本身还是继承它,都没有问题。super只在适当地支持多重继承时才需要(并且只有当每个类都正确地使用它时,它才会工作)。一般来说,如果AnyClass没有定义/覆盖它,AnyClass.whatever将在AnyClass的祖先中查找whatever,这对于"调用父方法的子类"和其他任何情况都适用!


Python 3有一个用于调用父方法的不同且更简单的语法。

如果Foo类继承自Bar,则可以通过super().__init__()Foo调用Bar.__init__:

1
2
3
4
5
class Foo(Bar):

    def __init__(self, *args, **kwargs):
        # invoke Bar.__init__
        super().__init__(*args, **kwargs)


许多答案都解释了如何从父类调用子类中重写的方法。

然而

"how do you call a parent class's method from child class?"

也可以是:

"how do you call inherited methods?"

您可以调用继承自父类的方法,就像它们是子类的方法一样,只要它们没有被覆盖。

例如在python3中:

1
2
3
4
5
6
7
8
9
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有助于理解如何访问继承的方法。


下面是一个使用super()的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#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的旧的和新的风格的类,但很常用,例如在构造函数:

1
2
3
4
class Foo(Bar):
    def __init__(self):
        super(Foo, self).__init__()
        self.baz = 5


我建议使用CLASS.__bases__像这样的东西

1
2
3
4
5
6
7
8
9
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()


如果你不知道你可能会得到多少争论,并且想把它们都传递给孩子:

1
2
3
4
class Foo(bar)
    def baz(self, arg, *args, **kwargs):
        # ... Do your thing
        return super(Foo, self).baz(arg, *args, **kwargs)

(来自:Python——覆盖_init__的最干净的方法,在super()调用之后必须使用可选kwarg ?)


python中也有一个super()。

说明如何从子类方法调用超类方法的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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版本中是可执行的。


在本例中,cafec_param是基类(父类),abc是子类。abc调用基类中的AWC方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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


在python2中,我使用super()时运气不太好。我用了所以线程如何引用python中的父方法?然后,我添加了我自己的小技巧,我认为这是可用性的改进(特别是如果您有很长的类名)。

在一个模块中定义基类:

1
2
3
4
5
 # myA.py

class A():    
    def foo( self ):
        print"foo"

然后将类导入另一个模块as parent:

1
2
3
4
5
6
7
# myB.py

from myA import A as parent

class B( parent ):
    def foo( self ):
        parent.foo( self )   # calls 'A.foo()'


1
2
3
4
5
6
7
8
9
10
11
12
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()

1
2
3
4
5
6
7
8
9
10
11
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()


这是一个更抽象的方法:

1
super(self.__class__,self).baz(arg)