fbpx
维基百科

C3线性化

在计算机科学中,C3算法主要用在多重继承中,确定子类应该继承哪一个父类的方法。换句话说,C3超类线性化的输出是确定性的方法解析次序MRO:Method Resolution Order)。

描述

C3算法得名于它实现了一致性于三种重要特性:

  • 基于一致性扩展的优先图英语precedence graph
  • 局部优先原则(比如A继承B和C,C继承B,那么A读取父类方法,应该优先使用C的方法而不是B的方法),
  • 单调性原则(即子类不改变父类的方法搜索顺序)。

在1996年的OOPSLA会议上,发表的论文《Dylan的单调超类线性化》[1],首次提出了C3超类线性化。它在2012年1月被适配到了Open Dylan实现[2],跟从了一个增进的提议[3]Python 2.3[4][5]Raku[6]Parrot[7]SolidityPGF/TikZ英语PGF/TikZ的面向对象语言模块[8]等,将它选作方法解析的默认算法。Perl 5语言从版本5.10.0起将它作为可选的、非默认的MRO[9]。早期版本Perl 5有称为Class::C3一个扩展实现曾发布于CPAN[10]

Python创始人Guido van Rossum这样总结C3超类线性化:“基本上,在C3背后的想法是,如果你写下在复杂的类层级中继承关系所施加的所有次序规则,这个算法将确定出满足所有这些规则的这些类的一个单调次序。如果不能确定出这样的次序,这个算法会失败。”[11]

算法

一个类的C3超类线性化,是这个类加上它的这些父类的线性化和这些父类自身的列表的唯一性归并的总和。这些父类的列表作为给这个归并过程的最后实际参数,保持了这些直接父类的局部优先次序。

完成父类的线性化和父类列表的归并,选择这些列表的头部中第一个符合条件者,它不出现在任何这些列表的尾部(一个列表的除了第一个元素的所有元素)之中。注意一个良好头部,可以同时出现为多个列表的第一个元素,但是禁止它出现在任何其他地方。将选择的元素从以它作为头部的所有列表中移除,并将它填加到输出列表。重复选择并移除良好头部并扩展输出列表的过程,直到所有余下的列表被竭尽。如果在某一点上,因为所有余下列表的头部都出现在某个列表的尾部中,而没有良好头部可选,那么由于在继承层级中依赖的不一致次序,归并过程不能计算下去,故而最初类的线性化不存在。

计算一个类的线性化的一种朴素分治法,可以采用递归算法来为归并子例程找到父类的线性化。但是,这将在出现环状类层级时导致无限循环递归。为了检测这种环并打破无限递归,并重新利用前面计算的结果作为一种优化,递归调用应当通过缓存或记忆化的方式屏蔽重入以前的实际参数。

这个算法类似于找到拓扑次序

例子

给定

 
一个C3线性化的依赖图例子
 class O class A extends O class B extends O class C extends O class D extends O class E extends O class K1 extends A, B, C class K2 extends D, B, E class K3 extends D, A class Z extends K1, K2, K3 
Z的线性化计算: L(O) := [O] // O的线性化就是平凡的单例列表[O],因为O没有父类 L(A) := [A] + merge(L(O), [O]) // A的线性化是A加上它的父类的线性化与父类列表的归并 = [A] + merge([O], [O]) = [A, O] // 其结果是简单的将A前置于它的单一父类的线性化 L(B) := [B, O] // B、C、D和E的线性化的计算类似于A L(C) := [C, O] L(D) := [D, O] L(E) := [E, O] L(K1) := [K1] + merge(L(A), L(B), L(C), [A, B, C]) // 首先找到K1的父类的线性化L(A)、L(B)和L(C),接着将它们归并于父类列表[A, B, C] = [K1] + merge([A, O], [B, O], [C, O], [A, B, C]) // 类A是第一个归并步骤的良好候选者,因为它只出现为第一个和最后一个列表的头部元素。 = [K1, A] + merge([O], [B, O], [C, O], [B, C]) // 类O不是第二个归并步骤的良好候选者,因为它还出现在列表2和列表3的尾部中;但是类B是良好候选者 = [K1, A, B] + merge([O], [O], [C, O], [C]) // 类C是良好候选者;类O仍出现在列表3的尾部中 = [K1, A, B, C] + merge([O], [O], [O]) // 最后,类O是有效候选者,这还竭尽了所有余下的列表 = [K1, A, B, C, O] L(K2) := [K2] + merge(L(D), L(B), L(E), [D, B, E]) = [K2] + merge([D, O], [B, O], [E, O], [D, B, E]) // 选择D = [K2, D] + merge([O], [B, O], [E, O], [B, E]) // 不选O,选择B = [K2, D, B] + merge([O], [O], [E, O], [E]) // 不选O,选择E = [K2, D, B, E] + merge([O], [O], [O]) // 选择O = [K2, D, B, E, O] L(K3) := [K3] + merge(L(D), L(A), [D, A]) = [K3] + merge([D, O], [A, O], [D, A]) // 选择D = [K3, D] + merge([O], [A, O], [A]) // 不选O,选择A = [K3, D, A] + merge([O], [O]) // 选择O = [K3, D, A, O] L(Z) := [Z] + merge(L(K1), L(K2), L(K3), [K1, K2, K3]) = [Z] + merge([K1, A, B, C, O], [K2, D, B, E, O], [K3, D, A, O], [K1, K2, K3]) // 选择K1 = [Z, K1] + merge([A, B, C, O], [K2, D, B, E, O], [K3, D, A, O], [K2, K3]) // 不选A,选择K2 = [Z, K1, K2] + merge([A, B, C, O], [D, B, E, O], [K3, D, A, O], [K3]) // 不选A,不选D,选择K3 = [Z, K1, K2, K3] + merge([A, B, C, O], [D, B, E, O], [D, A, O]) // 不选A,选择D = [Z, K1, K2, K3, D] + merge([A, B, C, O], [B, E, O], [A, O]) // 选择A = [Z, K1, K2, K3, D, A] + merge([B, C, O], [B, E, O], [O]) // 选择B = [Z, K1, K2, K3, D, A, B] + merge([C, O], [E, O], [O]) // 选择C = [Z, K1, K2, K3, D, A, B, C] + merge([O], [E, O], [O]) // 不选O,选择E = [Z, K1, K2, K3, D, A, B, C, E] + merge([O], [O], [O]) // 选择O = [Z, K1, K2, K3, D, A, B, C, E, O] // 完成 

用Python3展示例子

首先,定义一个元类来允许对象通过名字简明表示:

class Type(type): def __repr__(cls): return cls.__name__ class O(object, metaclass=Type): pass 

O通过名字表示自身,而不采用默认表示形式:

>>> O O >>> class X: pass ...  >>> X <class '__main__.X'> 

接着构造这个继承树:

class A(O): pass class B(O): pass class C(O): pass class D(O): pass class E(O): pass class K1(A, B, C): pass class K2(D, B, E): pass class K3(D, A): pass class Z(K1, K2, K3): pass 

然后就可看到结果:

>>> Z.mro() [Z, K1, K2, K3, D, A, B, C, E, O, <class 'object'>] 

用Raku展示例子

Raku默认的对类使用C3线性化:

class A {} class B {} class C {} class D {} class E {} class K1 is A is B is C {} class K2 is D is B is E {} class K3 is D is A {} class Z is K1 is K2 is K3 {} say Z.^mro; # OUTPUT: ((Z) (K1) (K2) (K3) (D) (A) (B) (C) (E) (Any) (Mu)) 

AnyMu是所有Raku对象从其继承的类型。

参考文献

  1. ^ A Monotonic Superclass Linearization for Dylan. OOPSLA '96 Conference Proceedings. ACM Press: 69–82. 1996-06-28 [2018-02-02]. ISBN 0-89791-788-X. doi:10.1145/236337.236343. (原始内容于2018-12-14). 
  2. ^ . [2021-12-10]. (原始内容存档于2020-08-26). 
  3. ^ . [2021-12-10]. (原始内容存档于2017-07-03). 
  4. ^ Python 2.3's use of C3 MRO. [2018-02-02]. (原始内容于2020-08-20). 
  5. ^ Tutorial for practical applications of C3 linearization using Python. [2018-02-02]. (原始内容于2020-07-05). 
  6. ^ Perl 6's use of the C3 MRO. [2018-02-02]. (原始内容于2016-06-17). 
  7. ^ . [2018-02-02]. (原始内容存档于2007-02-08). 
  8. ^ Tantau, Till. The TikZ & PGF Manual (PDF) 3.0.1a. 2015-08-29: 956 [2017-08-14]. (原始内容 (PDF)于2020-08-26). 
  9. ^ C3 MRO available in Perl 5.10 and newer. [2018-02-02]. (原始内容于2013-09-13). 
  10. ^ Perl 5 extension for C3 MRO on CPAN. [2018-02-02]. (原始内容于2013-06-06). 
  11. ^ van Rossum, Guido. . The History of Python. 23 June 2010 [18 January 2018]. (原始内容存档于2018-02-08). 

c3线性化, 在计算机科学中, c3算法主要用在多重继承中, 确定子类应该继承哪一个父类的方法, 换句话说, c3超类线性化的输出是确定性的方法解析次序, method, resolution, order, 目录, 描述, 算法, 例子, 用python3展示例子, 用raku展示例子, 参考文献描述, 编辑c3算法得名于它实现了一致性于三种重要特性, 基于一致性扩展的优先图, 英语, precedence, graph, 局部优先原则, 比如a继承b和c, c继承b, 那么a读取父类方法, 应该优先使用c的方法. 在计算机科学中 C3算法主要用在多重继承中 确定子类应该继承哪一个父类的方法 换句话说 C3超类线性化的输出是确定性的方法解析次序 MRO Method Resolution Order 目录 1 描述 2 算法 2 1 例子 2 2 用Python3展示例子 2 3 用Raku展示例子 3 参考文献描述 编辑C3算法得名于它实现了一致性于三种重要特性 基于一致性扩展的优先图 英语 precedence graph 局部优先原则 比如A继承B和C C继承B 那么A读取父类方法 应该优先使用C的方法而不是B的方法 单调性原则 即子类不改变父类的方法搜索顺序 在1996年的OOPSLA会议上 发表的论文 Dylan的单调超类线性化 1 首次提出了C3超类线性化 它在2012年1月被适配到了Open Dylan实现 2 跟从了一个增进的提议 3 Python 2 3 4 5 Raku 6 Parrot 7 Solidity和PGF TikZ 英语 PGF TikZ 的面向对象语言模块 8 等 将它选作方法解析的默认算法 Perl 5语言从版本5 10 0起将它作为可选的 非默认的MRO 9 早期版本Perl 5有称为Class C3一个扩展实现曾发布于CPAN 10 Python创始人Guido van Rossum这样总结C3超类线性化 基本上 在C3背后的想法是 如果你写下在复杂的类层级中继承关系所施加的所有次序规则 这个算法将确定出满足所有这些规则的这些类的一个单调次序 如果不能确定出这样的次序 这个算法会失败 11 算法 编辑一个类的C3超类线性化 是这个类加上它的这些父类的线性化和这些父类自身的列表的唯一性归并的总和 这些父类的列表作为给这个归并过程的最后实际参数 保持了这些直接父类的局部优先次序 完成父类的线性化和父类列表的归并 选择这些列表的头部中第一个符合条件者 它不出现在任何这些列表的尾部 一个列表的除了第一个元素的所有元素 之中 注意一个良好头部 可以同时出现为多个列表的第一个元素 但是禁止它出现在任何其他地方 将选择的元素从以它作为头部的所有列表中移除 并将它填加到输出列表 重复选择并移除良好头部并扩展输出列表的过程 直到所有余下的列表被竭尽 如果在某一点上 因为所有余下列表的头部都出现在某个列表的尾部中 而没有良好头部可选 那么由于在继承层级中依赖的不一致次序 归并过程不能计算下去 故而最初类的线性化不存在 计算一个类的线性化的一种朴素分治法 可以采用递归算法来为归并子例程找到父类的线性化 但是 这将在出现环状类层级时导致无限循环递归 为了检测这种环并打破无限递归 并重新利用前面计算的结果作为一种优化 递归调用应当通过缓存或记忆化的方式屏蔽重入以前的实际参数 这个算法类似于找到拓扑次序 例子 编辑 给定 一个C3线性化的依赖图例子 class O class A extends O class B extends O class C extends O class D extends O class E extends O class K1 extends A B C class K2 extends D B E class K3 extends D A class Z extends K1 K2 K3 Z 的线性化计算 L O O O的线性化就是平凡的单例列表 O 因为O没有父类 L A A merge L O O A的线性化是A加上它的父类的线性化与父类列表的归并 A merge O O A O 其结果是简单的将A前置于它的单一父类的线性化 L B B O B C D和E的线性化的计算类似于A L C C O L D D O L E E O L K1 K1 merge L A L B L C A B C 首先找到K1的父类的线性化L A L B 和L C 接着将它们归并于父类列表 A B C K1 merge A O B O C O A B C 类A是第一个归并步骤的良好候选者 因为它只出现为第一个和最后一个列表的头部元素 K1 A merge O B O C O B C 类O不是第二个归并步骤的良好候选者 因为它还出现在列表2和列表3的尾部中 但是类B是良好候选者 K1 A B merge O O C O C 类C是良好候选者 类O仍出现在列表3的尾部中 K1 A B C merge O O O 最后 类O是有效候选者 这还竭尽了所有余下的列表 K1 A B C O L K2 K2 merge L D L B L E D B E K2 merge D O B O E O D B E 选择D K2 D merge O B O E O B E 不选O 选择B K2 D B merge O O E O E 不选O 选择E K2 D B E merge O O O 选择O K2 D B E O L K3 K3 merge L D L A D A K3 merge D O A O D A 选择D K3 D merge O A O A 不选O 选择A K3 D A merge O O 选择O K3 D A O L Z Z merge L K1 L K2 L K3 K1 K2 K3 Z merge K1 A B C O K2 D B E O K3 D A O K1 K2 K3 选择K1 Z K1 merge A B C O K2 D B E O K3 D A O K2 K3 不选A 选择K2 Z K1 K2 merge A B C O D B E O K3 D A O K3 不选A 不选D 选择K3 Z K1 K2 K3 merge A B C O D B E O D A O 不选A 选择D Z K1 K2 K3 D merge A B C O B E O A O 选择A Z K1 K2 K3 D A merge B C O B E O O 选择B Z K1 K2 K3 D A B merge C O E O O 选择C Z K1 K2 K3 D A B C merge O E O O 不选O 选择E Z K1 K2 K3 D A B C E merge O O O 选择O Z K1 K2 K3 D A B C E O 完成 用Python3展示例子 编辑 首先 定义一个元类来允许对象通过名字简明表示 class Type type def repr cls return cls name class O object metaclass Type pass 类O通过名字表示自身 而不采用默认表示形式 gt gt gt O O gt gt gt class X pass gt gt gt X lt class main X gt 接着构造这个继承树 class A O pass class B O pass class C O pass class D O pass class E O pass class K1 A B C pass class K2 D B E pass class K3 D A pass class Z K1 K2 K3 pass 然后就可看到结果 gt gt gt Z mro Z K1 K2 K3 D A B C E O lt class object gt 用Raku展示例子 编辑 Raku默认的对类使用C3线性化 class A class B class C class D class E class K1 is A is B is C class K2 is D is B is E class K3 is D is A class Z is K1 is K2 is K3 say Z mro OUTPUT Z K1 K2 K3 D A B C E Any Mu Any和Mu是所有Raku对象从其继承的类型 参考文献 编辑 A Monotonic Superclass Linearization for Dylan OOPSLA 96 Conference Proceedings ACM Press 69 82 1996 06 28 2018 02 02 ISBN 0 89791 788 X doi 10 1145 236337 236343 原始内容存档于2018 12 14 News item on opendylan org 2021 12 10 原始内容存档于2020 08 26 Dylan Enhancement Proposal 3 C3 superclass linearization 2021 12 10 原始内容存档于2017 07 03 Python 2 3 s use of C3 MRO 2018 02 02 原始内容存档于2020 08 20 Tutorial for practical applications of C3 linearization using Python 2018 02 02 原始内容存档于2020 07 05 Perl 6 s use of the C3 MRO 2018 02 02 原始内容存档于2016 06 17 Parrot uses C3 MRO 2018 02 02 原始内容存档于2007 02 08 Tantau Till The TikZ amp PGF Manual PDF 3 0 1a 2015 08 29 956 2017 08 14 原始内容存档 PDF 于2020 08 26 C3 MRO available in Perl 5 10 and newer 2018 02 02 原始内容存档于2013 09 13 Perl 5 extension for C3 MRO on CPAN 2018 02 02 原始内容存档于2013 06 06 van Rossum Guido Method Resolution Order The History of Python 23 June 2010 18 January 2018 原始内容存档于2018 02 08 取自 https zh wikipedia org w index php title C3线性化 amp oldid 71574124, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。