隐式调用父类的初始化

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(相对于初始化以正确的顺序所有的父类)调用的超级构造函数时,而不是命名当前类( Bsuper(B, self).__init__(1, b, c)

--------------解决方案-------------

简短的回答:没有,没有办法隐式调用正确的__init__与正确的父类在Python 2.x的正确参数

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

见http://fuhm.net/super-harmful/的问题(有图片)的详细说明。

也许你正在寻找什么是元类?

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

您的代码无关的方法解析顺序。 方法解析进来多重继承的情况下,这是不是你的例子的情况下。 你的代码是完全错误的,因为你认为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 da

打印:

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

(修改后的版本的模板模式)。

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

对于单一继承,更好的方法是显式调用父类的方法,而无需调用super 。 这样做,你不必命名当前的类 ,但你仍然必须关心谁是父类。

良好的读取是:怎么,不-蟒蛇超级-DO最右的事情,在这个问题和特殊性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__
>>> ba
42
>>>

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

在给定的类定义方法总是裂伤双下划线属性,包括它们中定义的类的名称。所以,如果你藏引用的类名,错位形式,其中的实例可以看到它,你可以使用在调用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>

分类:蟒蛇 时间:2015-03-14 人气:0
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 3.899 (s). 10 q(s)