Python 里的多重继承
2013-09-29 15:27
399 查看
转自:http://christophor.blog.163.com/blog/static/16215437320107276239434/
Python 里的多重继承
Python支持多重继承,通过查看子类的类对象的__bases__就可以看到它继承的类元组。这里只是针对在多重继承下,子类实例调用子类的方法的原则进行介绍。我们以例子来说明一下:
class A():
_a = 1
def Afun(self):
print 'A'
def Common(self):
print 'A-common'
class A1():
def Common(self):
print 'A1-common'
class B(A,A1):
_b = 2
def Bfun(self):
print 'B'
b = B()
b.Common()
以上的代码输出的是A-common,可以看到python在处理多个基类时,是按继承的顺序来查找相应的属性(成员和方法等)
再看下面的代码,使A继承于AA,并且把方法移到基类AA上去:
class AA():
def Common(self):
print 'A-common'
class A( AA ):
_a = 1
def Afun(self):
print 'A'
class A1():
def Common(self):
print 'A1-common'
class B(A,A1):
_b = 2
def Bfun(self):
print 'B'
这样的输出还是:A-common,可以看到它是深度优先的,就是先找A是否具有Common方法,如果没有则从它的基类AA里寻找,如果都没有再到A1里找。
以上的结果对python的新类同样适用。
以上都比较简单,我们来看下在C++里令人烦躁的菱形继承在python里的表现如何。
class A():
_a = 1
def Afun(self):
print 'A'
def Common(self):
print 'A-common'
class B(A):
_b = 2
def Bfun(self):
print 'B'
def Common(self):
print 'B-common'
class C(A):
_c = 3
def CFun(self):
print 'C'
def Common(self):
print 'C-common'
class D(C,B):
_d = 4
def DFun(self):
print 'D'
d = D()
d.Common()
以上的代码输出:C-common
这也符合我们上面说的。
情况1,把C的Common方法注释掉
class C(A):
_c = 3
def CFun(self):
print 'C'
'''
def Common(self):
print 'C-common'
'''
这时输出的是:A-common
也符合我们的深度优先。
情况2,不改变C,我们改动A,把它变成新类形式(也就是使它继承于object)
class A(object):
_a = 1
def Afun(self):
print 'A'
def Common(self):
print 'A-common'
这是输出的结果是:B-common
这个就好像不符合我们刚才所说的规则了,这是为什么呢?
通过跟踪代码,终于找到原因了:其实是在执行d.Common()的时候,执行PyObject_GetAttr时调用tp->tp_getattro,而新类和旧类对应的原类的实现是不一样的:
旧的类(就是A没有继承object)tp->tp_getattro 是
instance_getattr(PyInstanceObject * inst, _object * name)
核心代码:深度查找
static PyObject *
class_lookup(PyClassObject *cp, PyObject *name, PyClassObject **pclass)
{
Py_ssize_t i, n;
PyObject *value = PyDict_GetItem(cp->cl_dict, name);
if (value != NULL) {
*pclass = cp;
return value;
}
n = PyTuple_Size(cp->cl_bases);
for (i = 0; i < n; i++) {
/* XXX What if one of the bases is not a class? */
PyObject *v = class_lookup(
(PyClassObject *)
PyTuple_GetItem(cp->cl_bases, i), name, pclass);
if (v != NULL)
return v;
}
return NULL;
}
新的类则是tp->tp_getattro 是
PyObject_GenericGetAttr(_object * obj, _object * name)
核心代码:顺序查找
mro = tp->tp_mro;
assert(mro != NULL);
assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro);
for (i = 0; i < n; i++) {
base = PyTuple_GET_ITEM(mro, i);
if (PyClass_Check(base))
dict = ((PyClassObject *)base)->cl_dict;
else {
assert(PyType_Check(base));
dict = ((PyTypeObject *)base)->tp_dict;
}
assert(dict && PyDict_Check(dict));
descr = PyDict_GetItem(dict, name);
if (descr != NULL)
break;
}
还有一个疑问就是tp->tp_mro是什么时候?怎么设置的?
通过跟踪代码发现tp->tp_mro设置是在生成类的时候设定的,通过
mro_implementation(PyTypeObject *type),而这个函数会过滤掉重复的。
所以新类形式的查找顺序是D -> C -> B -> A -> object,也就是tp->tp_mro元组的顺序。
Python 里的多重继承
Python支持多重继承,通过查看子类的类对象的__bases__就可以看到它继承的类元组。这里只是针对在多重继承下,子类实例调用子类的方法的原则进行介绍。我们以例子来说明一下:
class A():
_a = 1
def Afun(self):
print 'A'
def Common(self):
print 'A-common'
class A1():
def Common(self):
print 'A1-common'
class B(A,A1):
_b = 2
def Bfun(self):
print 'B'
b = B()
b.Common()
以上的代码输出的是A-common,可以看到python在处理多个基类时,是按继承的顺序来查找相应的属性(成员和方法等)
再看下面的代码,使A继承于AA,并且把方法移到基类AA上去:
class AA():
def Common(self):
print 'A-common'
class A( AA ):
_a = 1
def Afun(self):
print 'A'
class A1():
def Common(self):
print 'A1-common'
class B(A,A1):
_b = 2
def Bfun(self):
print 'B'
这样的输出还是:A-common,可以看到它是深度优先的,就是先找A是否具有Common方法,如果没有则从它的基类AA里寻找,如果都没有再到A1里找。
以上的结果对python的新类同样适用。
以上都比较简单,我们来看下在C++里令人烦躁的菱形继承在python里的表现如何。
class A():
_a = 1
def Afun(self):
print 'A'
def Common(self):
print 'A-common'
class B(A):
_b = 2
def Bfun(self):
print 'B'
def Common(self):
print 'B-common'
class C(A):
_c = 3
def CFun(self):
print 'C'
def Common(self):
print 'C-common'
class D(C,B):
_d = 4
def DFun(self):
print 'D'
d = D()
d.Common()
以上的代码输出:C-common
这也符合我们上面说的。
情况1,把C的Common方法注释掉
class C(A):
_c = 3
def CFun(self):
print 'C'
'''
def Common(self):
print 'C-common'
'''
这时输出的是:A-common
也符合我们的深度优先。
情况2,不改变C,我们改动A,把它变成新类形式(也就是使它继承于object)
class A(object):
_a = 1
def Afun(self):
print 'A'
def Common(self):
print 'A-common'
这是输出的结果是:B-common
这个就好像不符合我们刚才所说的规则了,这是为什么呢?
通过跟踪代码,终于找到原因了:其实是在执行d.Common()的时候,执行PyObject_GetAttr时调用tp->tp_getattro,而新类和旧类对应的原类的实现是不一样的:
旧的类(就是A没有继承object)tp->tp_getattro 是
instance_getattr(PyInstanceObject * inst, _object * name)
核心代码:深度查找
static PyObject *
class_lookup(PyClassObject *cp, PyObject *name, PyClassObject **pclass)
{
Py_ssize_t i, n;
PyObject *value = PyDict_GetItem(cp->cl_dict, name);
if (value != NULL) {
*pclass = cp;
return value;
}
n = PyTuple_Size(cp->cl_bases);
for (i = 0; i < n; i++) {
/* XXX What if one of the bases is not a class? */
PyObject *v = class_lookup(
(PyClassObject *)
PyTuple_GetItem(cp->cl_bases, i), name, pclass);
if (v != NULL)
return v;
}
return NULL;
}
新的类则是tp->tp_getattro 是
PyObject_GenericGetAttr(_object * obj, _object * name)
核心代码:顺序查找
mro = tp->tp_mro;
assert(mro != NULL);
assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro);
for (i = 0; i < n; i++) {
base = PyTuple_GET_ITEM(mro, i);
if (PyClass_Check(base))
dict = ((PyClassObject *)base)->cl_dict;
else {
assert(PyType_Check(base));
dict = ((PyTypeObject *)base)->tp_dict;
}
assert(dict && PyDict_Check(dict));
descr = PyDict_GetItem(dict, name);
if (descr != NULL)
break;
}
还有一个疑问就是tp->tp_mro是什么时候?怎么设置的?
通过跟踪代码发现tp->tp_mro设置是在生成类的时候设定的,通过
mro_implementation(PyTypeObject *type),而这个函数会过滤掉重复的。
所以新类形式的查找顺序是D -> C -> B -> A -> object,也就是tp->tp_mro元组的顺序。
相关文章推荐
- 我与python约个会:25. 企业级开发基础6:面向对象特征(继承)
- python中多重继承相关问题
- Python 类的定义、继承及使用对象
- Python的高级特性12:类的继承
- Python 类的继承
- python 多继承
- Python 5.3 多重继承
- Python 类继承,两种初始化(init)的区别
- Python进阶笔记(5)_ 继承
- python 类定义 继承
- python 面向对象——继承与多态
- Python面向对象——继承
- Python对象 继承 多态 获取对象信息 类的属性
- python类的继承
- Python - 对多继承以及super的一些了解
- python之面向对象之继承
- python 多重继承
- python 类 六:继承自动寻找父类
- python面向对象初学(类的继承)
- python学习(6)继承