Implicitly invoking parent class initializer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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) |
在上面的代码,commented出
它出现在这两个超级constructor呼叫为
有一些的方式在Python 2。x,我可以保持良好的()(私营initializing登两类所有的父母在正确的时候打电话给超阶)命名的交底不随流类(《
简短回答:不,没有办法用Python2.x中正确父类的正确参数隐式调用右边的
顺便说一下,这里显示的代码是不正确的:如果使用super().
请参阅http://fuhm.net/super-harmable/了解有关该问题的详细描述(带图片)。
您的代码与方法解析顺序无关。方法解析出现在多重继承的情况下,而不是您的示例。您的代码是完全错误的,因为您假定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> 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> >>> |
所以当你应该打电话给:
1 | super(B, self).__init__(1, b, c) |
你确实在打电话:
1 2 | # super(self.__class__, self).__init__(1, b, c) super(C, self).__init__(1, b, c) |
编辑:试图更好地回答这个问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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 |
印刷品:
1 2 3 4 5 | D._init B._init C._init A._init 3 |
(模板模式的修改版本)。
现在父母的方法实际上是隐式调用的,但是我必须同意python zen的说法,因为代码的可读性较低,而且收益也很低,所以显式比隐式更好。但是要注意,所有
对于单个继承,更好的方法是显式调用父级的方法,而不调用
好的读物是:pythons super是如何做正确的事情的,这个问题中建议的链接,特别是python的super很漂亮,但是你不能使用它。
如果层次结构可能发生变化,则是不良设计的症状,并且会对使用该代码的所有部分产生影响,因此不应鼓励使用该代码。
编辑2
我想到了另一个例子,但它使用元类。URWID库使用元类在类中存储属性
前任:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | >>> 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 >>> |
也许你要找的是元类?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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() |
打印"我是甲级学生"
元类所做的是覆盖B类(而不是对象)的初始创建,并确保每个B对象的内置字典现在包含一个基数组,您可以在其中查找B的所有基类。
据我所知,以下工作并不常见。但它似乎确实有效。
给定类定义中的方法总是会破坏双下划线属性,以包括在其中定义的类的名称。因此,如果您在实例可以看到的地方以名称损坏的形式存储对类的引用,那么可以在对
通过在基类上实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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 |
并且,做了类似的事情,但是使用一个元类并将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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 |
同时运行这些文件,作为一个源文件:
1 2 3 4 5 6 7 8 9 10 11 | % 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> |