class A(object):
    def __init__(self, a, b, c):
        #super(A, self).__init__()
        super(self.__class__, self).__init__()


class B(A):
    def __init__(self, b, c):
        print super(B, self)
        print super(self.__class__, self)
        #super(B, self).__init__(1, b, c)
        super(self.__class__, self).__init__(1, b, c)

class C(B):
    def __init__(self, c):
        #super(C, self).__init__(2, c)
        super(self.__class__, self).__init__(2, c)
C(3)

在上面的代码中,注释掉__init__电话出现在被普遍接受的“聪明”的方式来做到超类的初始化。然而,在事件的类层次结构很可能会改变,我一直使用未加注释的形式,直到最近。

看来,在调用在上述层次B超级构造,即B.__init__再次调用,self.__class__实际上是C,不B因为我一直认为。

是否有某种方式在Python的2.x的,我可以保持适当的MRO(相对于初始化以正确的顺序所有父类)调用超构造函数时,虽然没有在命名当前类(B super(B, self).__init__(1, b, c))吗

有帮助吗?

解决方案

简短的回答:没有,有没有办法隐含调用与在Python 2.x的右父类的正确观点的权利__init__

另外,如下所示的代码不正确:如果您使用超()__init__,然后在您的层次结构中的所有类都必须在__init__方法相同的签名。否则,你的代码可以停止工作,如果你介绍一个新的子类使用多重继承。

请参阅 http://fuhm.net/super-harmful/ 获得的一个较长的描述问题(有图片)。

其他提示

您的代码无关与方法解析顺序。方法分辨率的问题在多重继承的情况下,这是不是你的例子的情况下。您的代码是完全错误的,因为你认为self.__class__实际上是同一类,其中定义的方法之一,这是错误的:

>>> class A(object):
...     def __init__(self):
...         print self.__class__
... 
>>> 
>>> class B(A):
...     def __init__(self):
...         A.__init__(self)
... 
>>> B()
<class '__main__.B'>
<__main__.B object at 0x1bcfed0>
>>> A()
<class '__main__.A'>
<__main__.A object at 0x1bcff90>
>>> 

所以,当你应该叫:

super(B, self).__init__(1, b, c)

您确实调用:

# super(self.__class__, self).__init__(1, b, c)
super(C, self).__init__(1, b, c)

修改:尝试更好地回答这个问题。

class A(object):
    def __init__(self, a):
        for cls in self.__class__.mro():
            if cls is not object:
                cls._init(self, a)
    def _init(self, a):
        print 'A._init'
        self.a = a

class B(A):
    def _init(self, a):
        print 'B._init'

class C(A):
    def _init(self, a):
        print 'C._init'

class D(B, C):
    def _init(self, a):
        print 'D._init'


d = D(3)
print d.a

打印:

D._init
B._init
C._init
A._init
3

(A改性模板图案的版本)。

现在父母的方法真的叫含蓄,但我有python的禅宗,其中明确优于隐式,因为代码是较小的可读性和增益差同意。但要注意,所有_init方法具有相同的参数,你不能完全忘了父母,我不建议这样做。

有关单继承,更好的方法是显式调用父方法,而不调用super。这样做,你就不必的命名当前类的,但你仍然必须在意谁是父类。

好读是:如何,不-蟒蛇超办-the-右事情,并在问题和特殊性 Python的超级俏皮建议的联系,但你不能用它

如果层次结构可能改变是糟糕的设计的症状,并在所有的部件后果谁正在使用的代码,不应该被鼓励。

修改2

另一个例子是我一点,但其使用的元类。 Urwid库用途元类存储属性,__super,在课堂上这样那你只需要访问该属性。

例如:

>>> class MetaSuper(type):
...     """adding .__super"""
...     def __init__(cls, name, bases, d):
...         super(MetaSuper, cls).__init__(name, bases, d)
...         if hasattr(cls, "_%s__super" % name):
...             raise AttributeError, "Class has same name as one of its super classes"
...         setattr(cls, "_%s__super" % name, super(cls))
... 
>>> class A:
...  __metaclass__ = MetaSuper
...  def __init__(self, a):
...   self.a = a
...   print 'A.__init__'
... 
>>> class B(A):
...  def __init__(self, a):
...   print 'B.__init__'
...   self.__super.__init__(a)
... 
>>> b = B(42)
B.__init__
A.__init__
>>> b.a
42
>>> 

也许你在找什么是元类?

class metawrap(type):
    def __new__(mcs,name, bases, dict):
        dict['bases'] = bases
        return type.__new__(mcs,name,bases,dict)

class A(object):
    def __init__(self):
        pass
    def test(self):
        print "I am class A"

class B(A):
    __metaclass__ = metawrap
    def __init__(self):
        pass
    def test(self):
        par = super(self.bases[0],self)
        par.__thisclass__.test(self)
foo = B()
foo.test()

打印 “我是类A”

什么是元类确实是压倒一切的B级(不是对象)的初始创建并确保内置的字典每个B对象现在包含一个基地阵列,在这里您可以找到B中的所有基类

据我所知,下面的操作并不常见。但它似乎工作。

方法在给定的类定义始终撕裂双下划线属性,包括他们在,所以定义,如果你在藏名称错位的形式向类的引用,其中实例可以看到它的类的名字,您可以使用在调用super

一个例子积攒对象本身上的参考文献中,通过实现对基类__new__

def mangle(cls, name):
    if not name.startswith('__'):
        raise ValueError('name must start with double underscore')
    return '_%s%s' % (cls.__name__, name)

class ClassStasher(object):
    def __new__(cls, *args, **kwargs):
        obj = object.__new__(cls)
        for c in cls.mro():
            setattr(obj, mangle(c, '__class'), c)
        return obj

class A(ClassStasher):
    def __init__(self):
        print 'init in A', self.__class
        super(self.__class, self).__init__()

class B(A):
    def __init__(self):
        print 'init in B', self.__class
        super(self.__class, self).__init__()

class C(A):
    def __init__(self):
        print 'init in C', self.__class
        super(self.__class, self).__init__()

class D(B, C):
    def __init__(self):
        print 'init in D', self.__class
        super(self.__class, self).__init__()


d = D()    
print d

和,做了类似的事情,但使用一元类和类积攒的__class引用对象本身:

class ClassStasherType(type):
    def __init__(cls, name, bases, attributes):
        setattr(cls, mangle(cls, '__class'), cls)

class ClassStasher(object):
    __metaclass__ = ClassStasherType

class A_meta(ClassStasher):
    def __init__(self):
        print 'init in A_meta', self.__class
        super(self.__class, self).__init__()

class B_meta(A_meta):
    def __init__(self):
        print 'init in B_meta', self.__class
        super(self.__class, self).__init__()

class C_meta(A_meta):
    def __init__(self):
        print 'init in C_meta', self.__class
        super(self.__class, self).__init__()

class D_meta(B_meta, C_meta):
    def __init__(self):
        print 'init in D_meta', self.__class
        super(self.__class, self).__init__()


d = D_meta()    
print d

运行此一起,作为一个源文件:

% python /tmp/junk.py
init in D <class '__main__.D'>
init in B <class '__main__.B'>
init in C <class '__main__.C'>
init in A <class '__main__.A'>
<__main__.D object at 0x1004a4a50>
init in D_meta <class '__main__.D_meta'>
init in B_meta <class '__main__.B_meta'>
init in C_meta <class '__main__.C_meta'>
init in A_meta <class '__main__.A_meta'>
<__main__.D_meta object at 0x1004a4bd0>
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top