Python:在多次派生之后查询类的parentclass(“super()”不起作用)

2024-10-04 11:33:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我构建了一个使用基类的多个派生的类系统 (对象->类别1->类别2->类别3):

class class1(object):
 def __init__(self):
  print "class1.__init__()"
  object.__init__(self)

class class2(class1):
 def __init__(self):
  print "class2.__init__()"
  class1.__init__(self)


class class3(class2):
 def __init__(self):
  print "class3.__init__()"
  class2.__init__(self)

x = class3()

它按预期工作并打印:

^{pr2}$

现在我想替换这三条线

object.__init__(self)
...
class1.__init__(self)
...
class2.__init__(self)

像这样:

currentParentClass().__init__()
...
currentParentClass().__init__()
...
currentParentClass().__init__()

所以基本上,我想创建一个类系统 不用打字”classXYZ.doSomething公司()". 在

如上所述,我想得到“当前班级的 父类”。在

将三行替换为:

super(type(self), self).__init__()

不工作(它总是返回 当前实例->类2),并将导致 循环打印:

class3.__init__()
class2.__init__()
class2.__init__()
class2.__init__()
class2.__init__()
...

那么有没有一个函数可以给我当前类的 父类?在

谢谢你的帮助!在

亨利

--------------------在

编辑:

@伦纳特 好吧,也许我弄错了,但现在我想我没有把问题描述清楚够了。所以这个例子可以更好地解释:

让我们创建另一个子类

class class4(class3):
 pass

如果我们从class4派生一个实例会怎么样?在

y = class4()

我认为它显然执行了:

super(class3, self).__init__()

我们可以将其转化为:

class2.__init__(y)

这绝对不是目标(那将是class3.__init__(y)

现在进行大量父类函数调用-我不想在super()调用中用不同的基类名称重新实现所有函数。在

我还想提一下,我对Python的课程体系还不熟悉,所以我希望你对我有耐心。在


Tags: selfobjectinitdef基类类别classprint
3条回答

您在__class____bases__成员之后。类的父级如下所示:

>>> class A: pass

>>> class B(A): pass

>>> class C(B): pass

>>> C.__bases__[0]
<class __main__.B at ...>

>>> C.__bases__[0].__bases__[0]
<class __main__.A at ...>

但是,记住你的班级可以有多个家长。在

^{pr2}$

在我看来,你所做的事很少有价值。但是了解Python本身如何跟踪多重继承所需的家具是很有趣的。在

没有框架检查你是做不到的,这是不允许的。在

下面是我在网上找到的一个执行框架检查的实现:

import sys

class _super(object):
    __name__ = 'super'

    __slots__ = ('_super__super', '_super__method')

    def __init__(self, super, name):
        object.__setattr__(self, '_super__super', super)

        try:
            object.__setattr__(self, '_super__method', getattr(super, name))
        except AttributeError:
            object.__setattr__(self, '_super__method', name)

    def __call__(self, *p, **kw):
        method = object.__getattribute__(self, '_super__method')

        try:
            return method(*p, **kw)
        except TypeError:
            if type(method) is not str:
                raise

        super = object.__getattribute__(self, '_super__super')
        method = getattr(super, method)
        object.__setattr__(self, '_super__method', method)
        return method(*p, **kw)

    def __getattribute__ (self, name):
        super = object.__getattribute__(self, '_super__super')

        try:
            return getattr(super, name)
        except (TypeError, AttributeError):
            if name == 'super':
                raise TypeError("Cannot get 'super' object of 'super' object")

            raise

    def __setattr__(self, name, value):
        super = object.__getattribute__(self, '_super__super')
        object.__setattr__(super, name, value)

def _getSuper(self):
    frame = sys._getframe().f_back
    code = frame.f_code
    name = code.co_name

    cur_class = None

    for c in type(self).__mro__:
        try:
            m = getattr(c, name)
            func_code = m.func_code
        except AttributeError:
            func_code = None

        if func_code is code:
            cur_class = c
        elif cur_class is not None:
            break

    if cur_class is None:
        raise TypeError, "Can only call 'super' in a bound method"

    return _super(super(cur_class, self), name)

class autosuper(object):
    __slots__ = ()
    super = property(_getSuper)

使用代码时:

^{pr2}$

python3, ^{} is already magical上,并且可以在不传递类的情况下工作:

super().method(args)

如上所述,我要获取“当前类的父类”

但你知道的。在二班是一班。我想打电话给你。总是这样。所以你可以打电话给班一。在

但是当前类的父类的正确方法是super()。但你是这样用的:

super(type(self), self)

这会让你成为自我类的父类。在你的例子中self的类是class3,所以正如你所注意到的,它总是返回class2。正确的使用方法如下:

^{pr2}$

使用super()和直接调用类之间的区别在于,如果在层次结构的某个地方使用多重继承。Super会找出哪个是正确的类。在


更新:

当你定义一个class4并调用它时会发生什么?在

>>> class class4(class3):
...  pass
... 
>>> y = class4()
class3.__init__()
class2.__init__()
class1.__init__()

正如您所说,目标是调用class3.__init__()。这正是发生的事情,因为根据正常的继承规则,类4将从类3继承__init__。在

您希望class2.__init__()被调用,但我不明白您为什么要这样做。您从类3继承,因此它的__init__将被调用。它依次调用每个设计的class2.__init__。在

相关问题 更多 >