隐式调用父类的初始化
-
23-09-2019 - |
题
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>