Python: запрос родительского класса класса после нескольких дериваций («super ()» не работает) - PullRequest
0 голосов
/ 10 января 2011

Я построил систему классов, которая использует несколько производных базового класса (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__()

Теперь я хотел бы заменить 3 строки

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

на что-то вроде этого:

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

Итак, я хочу создать систему классов, в которой яне нужно вводить "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.__init__(y))

Теперь делаю много вызовов функций родительского класса - я не хочуРеализовать все мои функции с разными именами базовых классов в моих вызовах super ().

Я также хочу отметить, что я новичок в системе классов питонов, так что я надеюсь, что у вас естьтерпение со мной.

Ответы [ 3 ]

4 голосов
/ 10 января 2011

"Как упоминалось выше, я хочу получить" родительский класс текущего класса "."

Но ты это знаешь. В классе 2 это класс1. Итак, вы хотите позвонить в class1. Всегда. Тогда вы можете просто позвонить в class1.

Но правильный путь к родительскому классу текущего класса - super (). Но вы использовали это так:

super(type(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 унаследует __init__ от class3 в соответствии с обычными правилами наследования.

Вы ожидали, что class2.__init__() позвонят, но я не понимаю, почему вы этого ожидаете. Вы наследуете от class3, поэтому будет вызываться __init__. Это в свою очередь вызывает class2.__init__ за дизайн.

0 голосов
/ 31 августа 2014

Вы после __bases__ участника __class__.Родитель вашего класса доступен следующим образом:

>>> 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 отслеживает мебель, необходимую для множественного наследования.

0 голосов
/ 10 января 2011

Вы не можете сделать это без проверки кадра, и это осуждается.

Вот реализация, которую я нашел в сети, которая выполняет проверку кадра:

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

На python3, super() уже магический и может работать без прохождения класса:

super().method(args)
...