Python-Beyond the Basics--Inheritance & Subtype Polymorphism

原创 2016年08月29日 19:05:46

最近在看pluralsight的 python- beyond the basics 教程,学到好多东西。在这里记一下。

本节讲的是继承相关的知识。

Method Resolution Order

1. 定义

MRO 指明了在继承中,当类本身和基类中同时有多个同名函数定义的时候,应该如何查找最终智行的函数。本身是ordering of the inheritance graph.

2. 查看
YOUR_CLASS.__mro__ 或者是 YOUR_CLASS.mro()
区别在于__mro__产生的是tuple,mro()产生的是数组
任意class的mro 最后一个元素都是object class
例如:
<span style="font-family:Microsoft YaHei;">class A(object):
    def func(self):
        return 'A.func'

class B(A):
    def func(self):
        return 'B.func'

class C(A):
    def func(self):
        return 'C.func'

class D(C, B):
    pass
    
print D.mro()</span>

产生结果是:
<span style="font-family:Microsoft YaHei;">[<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>]</span>

注:在python2.7.8下,发现当class A 定义时没有继承object,则查看class的mro会报错。

3. 使用
对obj.method() 调用来说, python会在class的MRO列表中的class里依次查找class是否有匹配的函数,
一旦找到,就调用对应class的函数来执行。
因此对于上面的class D 如果执行:
<span style="font-family:Microsoft YaHei;"><span style="font-family:Microsoft YaHei;font-size:14px;">d = D()
d.func()</span></span>
则得到:
<span style="font-family:Microsoft YaHei;">'C.func'</span>
当对D的继承顺序修改,交换B,C的位置,则执行结果就变成了 "B.func".

4.计算

C3--python中计算MRO的算法,参考网址:The Python 2.3 Method Resolution Order  and  C3
C3 makes sure:
    1) subclass在 base class之前
    2) base class from class definition is preserved
    3) First two qualities are preserved no matter where you stat in the inheritance graph.

好像也不是很明白。根据第一个链接中,给出的计算方法:

对多继承结构中的类C来说,C的基类有B1, B2, ....Bn. 要计算类C的线性值(Linearization) L[C], 规则如下:
L[C] 是C加上 父类线性值和父类list的merge结果,公式如下:
L[C (B1, B2, ...Bn)] = C +merge (L[B1], L[B2],.....  L[Bn],  B1,  B2, ....., Bn)

特别地, L[ object ] =  object.  

merge的核心描述是:
take the head of the first list, i.e L[B1][0]; if this head is not in the tail of any of the other lists, then add it to the linearization of C and remove it from the lists in the merge, otherwise look at the head of the next list and take it, if it is a good head. Then repeat the operation until all the class are removed or it is impossible to find good heads. In this case, it is impossible to construct the merge, Python 2.3 will refuse to create the class C and will raise an exception.
对于只有一个基类B的类C来说, L[C(B)] = C + merge(L[B],B) = C + L[B]。
文章: Python MRO C3 给出了详细的解析。
具体的实现代码在github 中:functools.py 函数:_c3_merge 。
<span style="font-family:Microsoft YaHei;">def _c3_merge(sequences):
    """Merges MROs in *sequences* to a single MRO using the C3 algorithm.
    Adapted from http://www.python.org/download/releases/2.3/mro/.
    """
    result = []
    while True:
        sequences = [s for s in sequences if s]   # purge empty sequences
        if not sequences:
            return result
        for s1 in sequences:   # find merge candidates among seq heads
            candidate = s1[0]
            for s2 in sequences:
                if candidate in s2[1:]:
                    candidate = None
                    break      # reject the current head, it appears later
            else:
                break
        if candidate is None:
            raise RuntimeError("Inconsistent hierarchy")
        result.append(candidate)
        # remove the chosen candidate
        for seq in sequences:
            if seq[0] == candidate:
                del seq[0]
</span>
文章: Python MRO C3 总结说从动作上看就是捏住两端,拉直。(每个节点间绳子具有最大弹性,保证拉直,最小为两个节点多路径下的最大步长)”还是挺形象的。

5.应用

"The __mro__ attribute of the type lists the method resolution search order used by both getattr() and super()."

即 getattr 和 super都利用了MRO来查找method

Built-In Super Function

1. 定义

在理解了MRO的基础上,再看super就很容易了。
“Given a method resolution order and a class C,super() gives you a object which resolves methods using only the part of the MRO which comes after C”。
super() 其实是返回了一个proxy对象,该对象是用来路由method调用的。
def super(type, object_or_type):
     pass

2. 参数说明:

如果第二个参数被忽略,那么super的调用就返回的是unbound 对象,这种情况用的极少,pluralsight里面直接跳过了,但是看到有人分析了这种用法,也许可以参考一下:Python里让人精神分裂的super class
当第二个参数被指定的时候,称之为bound proxy,这个是常见的。

对于bound proxy来说,有两种类型:

1) instance-bound

 super(class, instance-of-class), 要求instance必须是class的实例(isinstance(instance, class)=true)。
调用super时,流程如下:
  • 拿到第二个参数的类型对应的MRO
  • 找到第一个参数class在MRO中的位置
  • 然后使用该class在MRO之后的所有class来用于解析method


2) class-bound: 

super(base-class, derived-class), 要求derived-class 必须是base-class的子类(更准确的是issubclass(derived-class, base-class)=true),否则抛异常。
当调用super class bound proxy时,过程如下:
  • python 拿到 derived class的MRO
  • 然后在MRO里面找到base class
  • 然后从base class后面的所有class中找到最先匹配函数的那个类。
注意到查找匹配类时,是从base class后面开始的,不包括base class本身。


3. 没有参数的super() 

在python3.x中添加了无参数的super()函数,具体含义是跟调用上下文有关。
1) 在instance method中,等同于 super(class-of-method, self) 
2 )  在class method中, 等同于 super( class-of-method, class)







【Python】第二周Python基础(下)

-
  • 1970年01月01日 08:00

问题解决 The hierarchy of the type is inconsistent

由于我在myeclipse里建了两个JAVA PROJECT项目,分别是A projiect和B projiect,项目A引用了一些JAR包,然后项目B引用了项目A,但是B没有引用A的JAR包,就出现...
  • zhq426
  • zhq426
  • 2012-10-30 12:49:37
  • 98969

Android RecyclerView的案例讲述和"The hierarchy of the type ViewHolder is inconsistent"错误解决

RecyclerView Android 提供的一个更强大的滚动控件---RecyclerView,是一个增强版的ListView。下面介绍其用法 RecyclerView位于V7包,因此需要导入...
  • dadaxiaoxiaode
  • dadaxiaoxiaode
  • 2017-02-21 14:17:52
  • 1174

关于 Eclipse hierarchy of the type is inconsistent错

出现这种错误的原因是因为继承的类或者所实现的接口使用了其他的jar包,这个jar包没有导入到当前的项目中。...
  • u014615677
  • u014615677
  • 2016-12-12 22:01:38
  • 214

svn 错误 以及 中文翻译

比较长,如何查找不方便的话,用查找“CTRL+F”吧  # # Simplified Chinese translation for subversion package # This file ...
  • caisini_vc
  • caisini_vc
  • 2010-06-03 10:17:00
  • 104292

错误处理:The hierarchy of the type MyMethodBeforeAdvice is inconsistent

学习 Spring的AOP编程的时候,要按照例子实现一个前置通知,需要继承MethodBeforeAdvice,但是一直提示The hierarchy of the type MyMethodBefo...
  • blacklife150614
  • blacklife150614
  • 2015-11-13 10:44:22
  • 1204

The hierarchy of the type EditLocationAction is inconsistent 错误原因之一

这种错误可能有多种原因。其中一种原因是:当前类A继承了某类B,而类B是由某C.jar所引入的,如果C.jar比原始项目的C.jar版本新,则会出现The hierarchy of the type E...
  • ljg888
  • ljg888
  • 2013-12-16 16:15:13
  • 4508

Android - 抑制lint的Android XML的警告:tools:ignore

抑制lint的Android XML的警告:tools:ignore本文地址:http://blog.csdn.net/caroline_wendyAndroid的XML经常会出现警告,对于一个良好的...
  • u012515223
  • u012515223
  • 2014-12-29 21:49:58
  • 12591

ArcEngine错误提示

错误代码 错误名称 错误描述 HRESULT:0x80040201 FDO_E_LOADING_RESOURCE “Failed to load a resource (string...
  • u011609113
  • u011609113
  • 2016-04-14 21:19:36
  • 7253

使用 lint 增强你的代码

更新: Android Lint needs sources to be compiled. Please build project before executing SonarQube an...
  • JugglerTao
  • JugglerTao
  • 2017-03-14 10:17:10
  • 2344
收藏助手
不良信息举报
您举报文章:Python-Beyond the Basics--Inheritance & Subtype Polymorphism
举报原因:
原因补充:

(最多只允许输入30个字)