从子类调用父类的方法?


606

在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中的实际限制,我的理解上的空白还是两者都有?


3
我认为命名父类并不是一个坏主意。当子类从多个父类继承时,它会有所帮助,因为您显式命名了父类。

7
虽然给班级命名是一个不错的主意,但一定要这么做。
johndodo 2014年

请注意Python 2和Python 3之间的超级处理方面的更改https://www.python.org/dev/peps/pep-3135/。不再需要对类进行命名(尽管至少在某些情况下可能还是个主意)。
jwpfox

Answers:


735

是的,但仅适用于新型类。使用super()功能:

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

对于python <3,请使用:

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

53
您还可以不执行“返回Bar.baz(self,arg)”吗?如果是这样,哪个会更好?

15
是的,可以,但是OP询问如何做到这一点,而没有在调用站点(本例中为Bar)中明确命名超类。
亚当·罗森菲尔德

7
super()具有多重继承功能很奇怪。它调用“下一个”类。那可能是父类,或者可能是某些完全不相关的类,出现在层次结构的其他位置。
史蒂夫·杰索普

6
我使用Python 2.x,执行此操作时收到“错误:必须为类型,而不是classobj”
Chris F

28
该语法super(Foo, self)适用于Python 2.x吗?在Python 3.x中,super()首选正确吗?
Trevor Boyd Smith,

143

Python也具有超级功能

super(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()

7
比Adam更好的例子,因为您演示了如何将新式类与对象基类一起使用。只是缺少指向新型类的链接。
塞缪尔

81
ImmediateParentClass.frotz(self)

无论直接父类定义frotz自己还是继承它,都将很好。 super仅在正确支持多重继承时才需要(只有在每个类都正确使用它的情况下才起作用)。通常,如果未定义或覆盖它,AnyClass.whateverwhateverAnyClasss的祖先中查找AnyClass,这对于“调用父方法的子类”以及其他任何情况都适用!


这要求在要执行此语句的范围内也要包含InstantParentClass。仅从模块导入对象将无济于事。
Tushar Vazirani

如果它是一个类方法怎么办?
Shiplu Mokaddim '18

@TusharVazirani如果父类是一个直接类parent,那么它在整个类的范围内,不是吗?
Yaroslav Nikitenko

1
@YaroslavNikitenko我正在谈论导入实例,而不是类。
Tushar Vazirani

1
@TusharVazirani现在我明白了,谢谢。我正在考虑从当前类的方法进行调用(如OP所述)。
Yaroslav Nikitenko

74

Python 3具有不同且更简单的语法来调用父方法。

如果Foo类继承Bar,然后Bar.__init__可以从调用Foo通过super().__init__()

class Foo(Bar):

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

5
很高兴听到python 3有更好的解决方案。问题来自python2.X。(还是)感谢你的建议。
jjohn 2016年

45

许多答案已经解释了如何从父级中调用已被子级覆盖的方法。

然而

“您如何从子类中调用父类的方法?”

也可能意味着:

“您如何称呼继承的方法?”

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

例如在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 对于了解如何访问继承的方法很有用。


@gizzmole在什么情况下不起作用?我很高兴添加任何与之相关的警告或警告,但我不知道您发布的链接与该答案的相关性。

@Ben对不起,我没有足够仔细地阅读您的答案。该答案没有回答有关如何重载函数的问题,而是回答了另一个问题。我删除了最初的评论。
gizzmole

@gizzmole啊,不用担心。我意识到这个答案不适用于重载函数,但是这个问题并未明确提及重载(尽管给出的perl示例确实显示了重载的情况)。绝大多数其他答案都涉及超载-这个是针对那些不需要它的人的。

@Ben如果我想使用C中定义的变量从另一个名为“ C”的类调用B()。baz()怎么办?我尝试在C类中执行B()。baz(),其中self.string是另一个val。当我执行死刑时,它什么也没给我
乔伊

@joey我不确定您要做什么,或者是否在此问题的范围内。字符串是局部变量-设置self.string不会执行任何操作。但是,在C类中,您仍然可以致电B().bar(string)
Ben

26

这是使用super()的示例:

#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

这不是一个不好的例子吗?我相信使用Super并不是真正安全,除非您的整个层次结构都是“新样式”类并正确调用Super()。init()
Jaykul 2014年

13

Python中也有一个super()。由于Python的旧类和新类,这有点奇怪,但是在构造函数中非常常用:

class Foo(Bar):
    def __init__(self):
        super(Foo, self).__init__()
        self.baz = 5

9

我建议使用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()

1
请记住,从引用量可以看出 这里 super,人们真的不愿意使用base,除非你正在做的事情非常深。如果您不喜欢超级,请看mro。使用mro的第一个条目比跟踪要使用的碱基中的条目更安全。Python中的多重继承可以向后扫描某些事物,而向后扫描其他事物,因此让语言展开进程是最安全的。
2014年


4

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版本中执行。


2

在此示例中,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

1

在Python 2中,我对super()不太满意。我在这个SO线程上使用了jimifiki的答案,如何在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()'

2
您必须使用 class A(object): 代替, class A(): 然后super()将起作用
blndev

我不确定是否要遵循。您是在类的定义中指的吗?显然,您必须以某种方式指示类具有父级,以便认为您可以引用父级!因为我在9个月前发布了这篇文章,所以我对细节有些模糊,但是我认为我的意思是Arun Ghosh,Lawrence,kkk等产生的示例不适用于Py2.x。相反,这是一种有效的方法,并且是引用父级的简单方法,因此您在做什么就更清楚了。(例如使用超级)
-BuvinJ

-1
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()

-4
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()

2
欢迎使用stackoverflow。大约十年前,这个问题已经得到了详细的解答,答案已经被接受并且在很大程度上被赞成,并且您的答案没有添加任何新内容。您可能想尝试回答最近的(最好是未回答的)问题。附带说明,编辑器中有一个按钮可以应用正确的代码格式。
bruno desthuilliers

-24

这是一个更抽象的方法:

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

15
self .__ class__不适用于super,因为self始终是实例,而其始终是实例的类。这意味着如果你使用超(个体经营.__ class__ ..在那类是从继承的类,它不会正常工作。
xitrium

16
只是为了强调,请勿使用此代码。它违反了super()的全部目的,即正确遍历MRO。
伊夫2012年

1
stackoverflow.com/a/19257335/419348说了为什么不打电话super(self.__class__, self).baz(arg)
AechoLiu 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.