Python:查询一个类';多次派生后的父类(“super()”不起作用)

Python:查询一个类';多次派生后的父类(“super()”不起作用),python,class,parent,super,Python,Class,Parent,Super,我构建了一个类系统,它使用基类的多个派生 (对象->类别1->类别2->类别3): 它按预期工作并打印: class3.__init__() class2.__init__() class1.__init__() 现在我想更换这三条线 object.__init__(self) ... class1.__init__(self) ... class2.__init__(self) 比如说: currentParentClass().__init__() ... currentParentCl

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

它按预期工作并打印:

class3.__init__()
class2.__init__()
class1.__init__()
现在我想更换这三条线

object.__init__(self)
...
class1.__init__(self)
...
class2.__init__(self)
比如说:

currentParentClass().__init__()
...
currentParentClass().__init__()
...
currentParentClass().__init__()
super(type(self), self)
>>> 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 ...>
基本上,我想创建一个类系统 不必键入“classXYZ.doSomething()”


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

将三行替换为:

super(type(self), self).__init__()
不起作用(它总是返回 当前实例->class2),并将导致无休止的 循环打印:

class3.__init__()
class2.__init__()
class2.__init__()
class2.__init__()
class2.__init__()
...
有没有一个函数可以给我当前类的 父类

谢谢你的帮助

亨利

-------------------- 编辑:

@伦纳特 好吧,也许我理解错了,但目前我认为我没有足够清楚地描述这个问题。因此,这个例子可能会更好地解释这个问题:

让我们创建另一个子类

class class4(class3):
 pass
现在,如果我们从类4派生一个实例,会发生什么

y = class4()
我认为它清楚地表明:

super(class3, self).__init__()
我们可以将其转化为:

class2.__init__(y)
这绝对不是目标(那将是
class3.\uuuu init\uuuuu(y)

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


我还想说的是,我对pythons的课程体系有点陌生,所以我希望你对我有耐心。

如果不进行框架检查,你就做不到,这是不可取的

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

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)
使用代码时,请执行以下操作:

class class1(autosuper):
    def __init__(self):
        print "class1.__init__()"
        self.super()

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


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

x = class3()        
打开并可以在不通过课程的情况下工作:

super().method(args)
如上所述,我想获取“当前类的父类”

但你知道的。在2班,它是1班。所以你想打电话给1班。总是这样你就可以打电话给1班了

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

currentParentClass().__init__()
...
currentParentClass().__init__()
...
currentParentClass().__init__()
super(type(self), self)
>>> 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 ...>
这将使你成为自我类的父类。在你的例子中self的类是class3,所以正如你所注意到的,它总是返回class2。正确的使用方法如下:

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

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


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


x = class3()
使用super()和直接调用类的区别在于,您是否在层次结构中的某个位置使用多重继承。Super然后会找出哪个是正确的类


更新:

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

>>> class class4(class3):
...  pass
... 
>>> y = class4()
class3.__init__()
class2.__init__()
class1.__init__()
正如您所说,目标是调用
class3.\uuu init\uuu()
。这正是发生的情况,因为根据正常的继承规则,class4将从class3继承
\uuuu init\uuuu


您希望调用
class2.\uuu init\uuuu()
,但我不明白您为什么希望这样。您从类3继承,因此调用的是
\uuuu init\uuu
。它依次调用
class2.\uuuuu init\uuuuu
每个设计。

您在
\uuuuuuu base\uuuuuuuu
成员之后。类的父级如下所示:

currentParentClass().__init__()
...
currentParentClass().__init__()
...
currentParentClass().__init__()
super(type(self), self)
>>> 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 ...>
>A类:合格
>>>B(A)级:及格
>>>丙(乙)级:及格
>>>C.___uuu基[0]
>>>C.uuuuuuu基[0]。uuuu基[0]
但是,记住你的班级可以有多位家长

>>> class D: pass

>>> class E(A,D): pass

>>> E.__bases__
(<class __main__.A at ...>, <class __main__.D at ...>)
>>D级:通过
>>>E级(A、D):及格
>>>E.。_u基地__
(, )

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

Urgl。好的,nosklo,很抱歉投了你的反对票,但是不要鼓励这个家伙在他不应该做的时候做这些事他提出了两种解决这个问题的方法。我理解为什么框架检查方式不受欢迎,但它是解决我的问题的解决方案。我认为,切换到python 3是另一个很好的建议。@Lennart Regebro:很高兴你否决了我。看起来stackoverflow至少正在改善——在过去,这一切都是为了回答这个问题,不管它有多糟糕。我认为你应该否决这个问题,though@henry:Python3和Python2的唯一区别在于,在Python3中,它将自行计算类名。感谢您的回答和建议,但您的解决方案肯定不是我想要的。我想创建多个子类并继承函数,这些函数必须调用其父类的函数,而不是“class3”(或任何其他硬编码的类名)。@henry:这不是问题。super()仍然是正确答案。请注意,硬编码的类名不是父类的类名,而是从中调用它的类的类名。super()所做的是找出父项是什么,这样您就不必硬编码父项的名称。所以super()对你来说是正确的答案。我认为这是一个误解。请看我的编辑上面。我希望这能把事情说清楚。这绝对是一个误解。:)你还是想要超级()。真的,答案更新了。调用的方法将是class3.\uuu init\uuu(y)。