ChatGPT解决这个技术问题 Extra ChatGPT

如何从 Python 中的子类调用父类的方法?

在 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的实际限制,我理解的差距还是两者兼而有之?

我认为父类的命名并不是一个坏主意。当子类从多个父类继承时,它会有所帮助,因为您明确命名了父类。
虽然命名一个类的选项不是一个坏主意,但被迫这样做肯定是一个坏主意。
请注意 Python 2 和 Python 3 之间的超级处理变化https://www.python.org/dev/peps/pep-3135/。不再需要为类命名(尽管至少有时可能仍然是个好主意)。

j
jason m

使用 super() 函数:

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

对于 Python < 3,您必须明确选择使用 new-style classes 并使用:

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

你能不也做“return Bar.baz(self, arg)”吗?如果是这样,哪个会更好?
是的,你可以,但是 OP 询问如何在调用站点(在本例中为 Bar)显式命名超类的情况下执行此操作。
super() 对于多重继承很奇怪。它调用“下一个”类。这可能是父类,或者可能是出现在层次结构中其他地方的一些完全不相关的类。
我使用 Python 2.x,执行此操作时出现“错误:必须是类型,而不是 classobj”
语法 super(Foo, self) 适用于 Python 2.x 是否正确?在 Python 3.x 中,super() 是首选,对吗?
M
MaBe

Python 也有 super

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

比 Adam 更好的示例,因为您演示了使用带有对象基类的新型类。只是缺少指向新型课程的链接。
Adam's 的好处是可以同时显示 Python2 和 Python3 形式。虽然此示例适用于两个版本,但“新式类”业务和 super() 的参数是 Python2 的工件 - 请参阅 Adam 的 Python 3 版本以获得更简洁的代码示例(在 Python3 中,所有类现在都是新式类,所以不需要显式地从 object 继承,并且 super() 不需要类和 self 参数,它只是 super())。
只调用 super().foo() 而不是 super(B, self).foo() 有什么区别吗?两者似乎都在工作。
i
industryworker3595112
ImmediateParentClass.frotz(self)

会很好,无论是直接父类定义 frotz 本身还是继承它。 super 仅在正确支持 multiple 继承时才需要(然后它只有在每个类都正确使用它时才有效)。通常,如果 AnyClass 未定义/覆盖 AnyClass 的祖先,AnyClass.whatever 将在 AnyClass 的祖先中查找 whatever,这适用于“子类调用父类的方法”以及任何其他事件!


这要求 ImmediateParentClass 也存在于要执行的该语句的范围内。仅从模块导入对象将无济于事。
如果它是一个类方法怎么办?
@TusharVazirani 如果父类是直接parent,它在整个类的范围内,不是吗?
@YaroslavNikitenko 我说的是导入一个实例,而不是类。
@TusharVazirani 现在我明白了,谢谢。我正在考虑从当前类的方法调用(如 OP 所述)。
A
Arun Ghosh

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

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

class Foo(Bar):

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

很高兴听到 python 3 有更好的解决方案。问题来自python 2.X。 (还是)感谢你的建议。
B
Ben

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

然而

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

也可能意味着:

“你怎么称呼继承的方法?”

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

例如在 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 啊,不用担心。我意识到这个答案不适用于重载函数,但是问题没有明确提到重载(尽管给出的 perl 示例确实显示了重载的情况)。绝大多数其他答案都涉及超载 - 这个是为那些不需要它的人准备的。
@Ben 如果我想使用 C 中定义的变量从另一个名为“C”的类中调用 B().baz() 怎么办?我尝试在 C 类中做 B().baz(),其中 self.string 是另一个 val。当我处决时,它什么也没给我
@joey我不确定您要做什么,或者它是否在这个问题的范围内。 String 是一个局部变量 - 设置 self.string 不会做任何事情。但是,在 C 类中,您仍然可以调用 B().bar(string)
y
yesnik

下面是一个使用 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()
l
lawrence

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

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

J
Joran Beasley

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

请记住,正如您从这里对 super 的引用量中可以看出的那样,除非您做的事情非常深入,否则人们真的不愿意使用基础。如果你不喜欢super,看看mro。获取 mro 中的第一个条目比跟踪要使用的基地中的哪个条目更安全。 Python 中的多重继承会向后扫描某些事物,而另一些则向前扫描,因此让语言展开该过程是最安全的。
C
Community

如果您不知道可能会得到多少参数,并且还想将它们全部传递给孩子:

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

(来自:Python - Cleanest way to override __init__ where an optional kwarg must be used after the super() call?


k
kkk

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


G
Georgy

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

C
Community

在 Python 2 中,我对 super() 的运气并不好。我在这个 SO 线程 how to refer to a parent method in python? 上使用了来自 jimifiki 的答案。然后,我添加了我自己的小改动,我认为这是对可用性的改进(特别是如果你有很长的类名)。

在一个模块中定义基类:

 # 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()'

您必须使用 class A(object): 而不是 class A(): 然后 super() 将起作用
我不确定我是否跟随。你的意思是在类的定义中?显然,你必须以某种方式表明一个类有一个父级,以便认为你可以引用一个父级!因为,我在 9 个月前发布了这个,我对细节有点模糊,但我认为我的意思是来自 Arun Ghosh、lawrence、kkk 等的示例不适用于 Py 2.x。相反,这是一种有效的方法,也是一种引用父级的简单方法,因此更清楚您在做什么。 (比如使用超级)
m
maryam mehboob
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()

p
philosofool

如果要调用任何类的方法,只需在该类的任何实例上调用 Class.method。如果您的继承相对干净,这也适用于子类的实例:

class Foo:
    def __init__(self, var):
        self.var = var
    
    def baz(self):
        return self.var

class Bar(Foo):
    pass

bar = Bar(1)
assert Foo.baz(bar) == 1

s
shim
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()

欢迎来到stackoverflow。大约十年前,这个问题已经得到了详细的回答,答案被接受并在很大程度上得到了支持,而您的答案并没有增加任何新内容。您可能想尝试回答最近的(最好是未回答的)问题。作为旁注,编辑器中有一个按钮可以应用正确的代码格式。
u
user806071

这是一个更抽象的方法:

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

self.__class__ 不适用于 super ,因为 self 始终是实例,其类始终是实例的类。这意味着如果您在一个类中使用 super(self.__class__.. 并且该类是从该类继承而来的,它将不再起作用。
只是为了强调,不要使用这个代码。它破坏了 super() 的全部目的,即正确遍历 MRO。
stackoverflow.com/a/19257335/419348 说为什么不打电话给 super(self.__class__, self).baz(arg)