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

发布于 2024-10-11 19:50:50 字数 1680 浏览 5 评论 0原文

我构建了一个使用基类的多个派生的类系统 (object->class1->class2->class3):

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

它按预期工作并打印:

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

现在我想

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

用这样的东西替换 3 行:

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

所以基本上,我想创建一个类系统,其中我 不必输入“classXYZ.doSomething()”。

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

将三行替换为:

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

不起作用(它总是返回父类 当前实例-> class2) 并将导致无穷无尽 循环打印:

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

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

感谢您的帮助!

亨利

--------------------

编辑:

@Lennart 好吧,也许我误解了你,但目前我认为我没有足够清楚地描述问题。所以这个例子可能会更好地解释它:

现在让我们创建另一个子类,

class class4(class3):
 pass

如果我们从 class4 派生一个实例会发生什么?

y = class4()

我认为它清楚地执行:

super(class3, self).__init__()

我们可以将其翻译为:

class2.__init__(y)

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

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

我还想提一下,我对 python 级系统有点陌生,所以我希望你对我有耐心。

I have built a class-system that uses multiple derivations of a baseclass
(object->class1->class2->class3):

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

It works as expected and prints:

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

Now I would like to replace the 3 lines

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

with something like this:

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

So basically, i want to create a class-system where i
don't have to type "classXYZ.doSomething()".

As mentioned above, I want to get the "current class's
parent-class".

Replacing the three lines with:

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

does NOT work (it always returns the parent-class of the
current instance -> class2) and will result in an endless
loop printing:

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

So is there a function that can give me the current class's
parent-class?

Thank you for your help!

Henry

--------------------

Edit:

@Lennart
ok maybe i got you wrong but at the moment i think i didn't describe the problem clearly enough.So this example might explain it better:

lets create another child-class

class class4(class3):
 pass

now what happens if we derive an instance from class4?

y = class4()

i think it clearly executes:

super(class3, self).__init__()

which we can translate to this:

class2.__init__(y)

this is definitly not the goal(that would be class3.__init__(y))

Now making lots of parent-class-function-calls - i do not want to re-implement all of my functions with different base-class-names in my super()-calls.

I also want to mention that I am kind of new to pythons-class system, so i hope you have patience with me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

挽梦忆笙歌 2024-10-18 19:50:50

“如上所述,我想获取‘当前班级的父班级’。”

但你知道。在class2中它是class1。所以你想调用class1。总是。那么你就可以调用class1。

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

super(type(self), self)

这将为你提供 self 类的父类。在你的例子中, 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.__init__()。这正是所发生的情况,因为根据正常的继承规则,class4 将从 class3 继承__init__

您期望 class2.__init__() 被调用,但我不明白为什么您会这样期望。您继承自 class3,因此它的 __init__ 将被调用。它依次根据设计调用class2.__init__

"As mentioned above, I want to get the "current class's parent-class"."

But you know it. In class2 it's class1. So you want to call class1. Always. So then you could just call class1.

But the correct way to the the current class's parent-class is super(). But you used it like this:

super(type(self), self)

And that will get you the parent class of the class of self. And the class of self in your case is class3, so as you note, it always return class2. The correct way of using it is as follows:

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

The difference between using super() and calling the class directly is if you are using multiple inheritance somewhere in the hierarchy. Super will then figure out which is the correct class.


Update:

What happens when you define a class4 and call it?

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

As you say, the goal is to call class3.__init__(). This is exactly what happens, as class4 will inherit __init__ from class3, according to normal inheritance rules.

You expected class2.__init__() to get called, but I don't understand why you expect that. You inherit from class3, so it's __init__ will be the one that is called. It in turn calls class2.__init__ per design.

哀由 2024-10-18 19:50:50

您正在寻找 __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 ...>

但是,请记住您的班级可以有多个父级。

>>> class D: pass

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

>>> E.__bases__
(<class __main__.A at ...>, <class __main__.D at ...>)

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

You are after the __bases__ member of __class__. The parent of your class is available like this:

>>> 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 ...>

But, remember your class can have multiple parents.

>>> class D: pass

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

>>> E.__bases__
(<class __main__.A at ...>, <class __main__.D at ...>)

What you are up to is, in my opinion, seldom worthwhile. But it is fun to know how Python itself keeps track of the furniture needed for multiple inheritance.

莫相离 2024-10-18 19:50:50

如果没有框架检查,你就无法做到这一点,而这是令人不悦的。

这是我在网上找到的一个进行框架检查的实现:

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

On python3, super() 已经很神奇了并且可以在不传递类的情况下工作:

super().method(args)

You can't do it without frame inspection, and that's frowned upon.

Here's a implementation I found on the net that does frame inspection:

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)

Your code when using it:

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

On python3, super() is already magical and can work without passing the class:

super().method(args)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文