为什么 MRO 中的类以这种方式排序?

2023-11-23

我的 Python MRO 有问题 对于这段代码:

class F: pass 
class G: pass 
class H: pass
class E(G,H): pass
class D(E,F): pass 
class C(E,G): pass
class B(C,H): pass
class A(D,B,E): pass

print(A.__mro__)

我得到这个输出:

(<class '__main__.A'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.G'>, <class '__main__.H'>, <class '__main__.F'>, <class 'object'>)

为什么我得到<class '__main__.C'> before <class '__main__.E'>?

我以为会是:

  1. A
  2. D,B,E
  3. E,F | C,H | G,H

等等


简而言之,因为C依赖于取决于E正如您在依赖图中看到的那样(O 是object):

enter image description here

蟒蛇的方法解析顺序 (MRO)工作的约束条件是如果一个类a是一个类的依赖b,它被放置在队列中晚于b.

现在更多的是理论:

在 Python 中,MRO 使用以下内容线性化 rule:

L[C(B1 ... Bn)] = C + 合并(L[B1] ... L[Bn], B1 ... Bn); and

L[object] = object

(source)

And the merge定义为:

取第一个列表的头部,即 L[B1][0];如果这个头不在任何其他列表的尾部,则将其添加到 C 的线性化中,并将其从合并的列表中删除,否则查看下一个列表的头并取出它,如果它是一个好头。然后重复操作,直到所有的类都被移除或者无法找到好的头。在这种情况下,不可能构造合并,Python 2.3 将拒绝创建 C 类并引发异常。

(source)

因此,对于您的情况,第一步是:

L[A] = A+ 合并(L[D],L[B],L[E])

让我们首先解决递归调用:

L[D] = D+ 合并(L[E],L[F]);
L[B] = B+ 合并(L[C],L[H]); and
L[E] = E+ 合并(L[G],L[H]).

还有更多的递归(我们只做H一次并且不要重做E):

L[F] = F+ 合并(L[O]);
L[C] = C+ 合并(L[E],L[G]);
L[G] = G+ 合并(L[O]); and
L[H] = H+ 合并(L[O]).

Since L[O] is O and merge(a)(对于一个对象是a)因此我们已经获得了序列H, G and F:

L[H] = (H, O).
L[G] = (G, O).
L[F] = (F, O).

现在我们可以计算L[E]:

L[E] = E+合并((G,O) , (H,O) ).

Since O两者都在尾部,它放在最后:

L[E] = (E,G,H,O).

现在我们可以计算L[C]:

L[C] = C+合并((E,G,H,O) , (G,O) );
L[C] = (C,E) + 合并( (G,H,O) , (G,O) );
L[C] = (C,E,G) + 合并( (H,O) , (O) );
L[C] = (C,E,G,H) + 合并( (O) , (O) );
*L[C] = (C,E,G,H,O).

And L[D]:

L[D] = D+合并((E,G,H,O) , (F,O) );
..;
L[D] = (D,E,G,H,F,O).

Next L[B]可以完全解决:

L[B] = B+合并((C,E,G,H,O) , (H,O) );
..;
L[B] = (B,C,E,G,H,O).

现在我们终于可以解决了:

L[A] = A+合并((D,E,G,H,F,O) , (B,C,E,G,H,O) , (E,G,H,O) );
L[A] = (A,D) + 合并( (E,G,H,F,O) , (B,C,E,G,H,O) , (E,G,H,O) );
L[A] = (A,D,B) + 合并( (E,G,H,F,O) , (C,E,G,H,O) , (E,G,H,O) );
L[A] = (A,D,B,C) + 合并( (E,G,H,F,O) , (E,G,H,O) , (E,G,H,O) );
L[A] = (A,D,B,C,E) + 合并( (G,H,F,O) , (G,H,O) , (G,H,O) );
L[A] = (A,D,B,C,E,G) + 合并( (H,F,O) , (H,O) , (H,O) );
L[A] = (A,D,B,C,E,G,H) + 合并( (F,O) , (O) , (O) );
L[A] = (A,D,B,C,E,G,H,F) + 合并( (O) , (O) , (O) );
L[A] = (A,D,B,C,E,G,H,F,O).

这是预期的行为。

A 效率不高我制作的合并函数可用于教育目的,它绝对没有针对生产进行优化:

def mro_merge(*args):
    for i,arg in enumerate(args):
        if len(arg) > 0:
            head = arg[0]
            for argb in args:
                if head in argb[1:]:
                    break
            else:
                newargs = tuple(argb if len(argb) > 0 and argb[0] != head else argb[1:] for argb in args)
                print('mro_merge(%s) = %s + mro_merge(%s)'%(args,head,newargs))
                yield head
                for x in mro_merge(*newargs):
                    yield x
                break

当你调用它时,它会生成:

>>> list(mro_merge(('G','O'),('H','O')))
mro_merge((('G', 'O'), ('H', 'O'))) = G + mro_merge((('O',), ('H', 'O')))
mro_merge((('O',), ('H', 'O'))) = H + mro_merge((('O',), ('O',)))
mro_merge((('O',), ('O',))) = O + mro_merge(((), ()))
['G', 'H', 'O']
>>> list(mro_merge( ('D','E','G','H','F','O') , ('B','C','E','G','H','O') , ('E','G','H','O') ))
mro_merge((('D', 'E', 'G', 'H', 'F', 'O'), ('B', 'C', 'E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O'))) = D + mro_merge((('E', 'G', 'H', 'F', 'O'), ('B', 'C', 'E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O')))
mro_merge((('E', 'G', 'H', 'F', 'O'), ('B', 'C', 'E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O'))) = B + mro_merge((('E', 'G', 'H', 'F', 'O'), ('C', 'E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O')))
mro_merge((('E', 'G', 'H', 'F', 'O'), ('C', 'E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O'))) = C + mro_merge((('E', 'G', 'H', 'F', 'O'), ('E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O')))
mro_merge((('E', 'G', 'H', 'F', 'O'), ('E', 'G', 'H', 'O'), ('E', 'G', 'H', 'O'))) = E + mro_merge((('G', 'H', 'F', 'O'), ('G', 'H', 'O'), ('G', 'H', 'O')))
mro_merge((('G', 'H', 'F', 'O'), ('G', 'H', 'O'), ('G', 'H', 'O'))) = G + mro_merge((('H', 'F', 'O'), ('H', 'O'), ('H', 'O')))
mro_merge((('H', 'F', 'O'), ('H', 'O'), ('H', 'O'))) = H + mro_merge((('F', 'O'), ('O',), ('O',)))
mro_merge((('F', 'O'), ('O',), ('O',))) = F + mro_merge((('O',), ('O',), ('O',)))
mro_merge((('O',), ('O',), ('O',))) = O + mro_merge(((), (), ()))
['D', 'B', 'C', 'E', 'G', 'H', 'F', 'O']
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 MRO 中的类以这种方式排序? 的相关文章

  • 我可以在 matplotlib 中的绘图左侧放置一个垂直颜色条吗?

    来自颜色条方法的 matplotlib 命令摘要 http matplotlib org api pyplot api html highlight colorbar matplotlib pyplot colorbar我知道关键字参数or
  • Discord.py 斜线命令在 cogs 中不起作用

    我正在构建一个不和谐的机器人 并且想要在 cogs 内使用斜杠命令 但这些命令不显示或工作 这是代码 cog guild ids 858573429787066368 861507832934563851 class Slash comma
  • 无法使用Python请求会话模块登录网站

    我刚刚开始进行网络抓取 对于我的第一个项目 我尝试使用 requests Session 登录 artofproblemsolving com 并访问另一个用户的帐户 这是我的代码 import requests LOGIN URL htt
  • lmfit模型拟合然后预测

    我正在领养lmfit进行曲线拟合并使用拟合模型进行预测 然而下面的代码并没有达到我想要的效果 能否请你帮忙 谢谢 import numpy as np from lmfit import Model def linearModel x a0
  • Python 中“is”运算符的语义是什么?

    如何is运算符确定两个对象是否相同 它是如何工作的 我找不到它的记录 来自文档 http docs python org reference datamodel html 每个对象都有一个身份 一个类型 和一个值 对象的身份 一旦发生就永远
  • 如何在Python中手动对数字列表进行排序?

    规格 Ubuntu 13 04 Python 3 3 1 背景 Python的初学者 遇到了这个 手动排序 问题 我被要求做的事情 让用户输入 3 个数值并将它们存储在 3 个不同的变量中 不使用列表或排序算法 手动将这 3 个数字从小到大
  • 使用 python 从 CSV 创建字典

    我有一个 CSV 格式的文件 其中 A B 和 C 是标题 我如何以Python方式将此CSV转换为以下形式的字典 A 1 B 4 C 7 A 2 B 5 C 8 A 3 B 6 C 9 到目前为止我正在尝试以下代码 import csv
  • 提高光线追踪命中功能的性能

    我有一个简单的 python 光线追踪器 渲染 200x200 的图像需要 4 分钟 这对于我的口味来说绝对是太多了 我想改善这种情况 几点 我为每个像素发射多条光线 以提供抗锯齿功能 每个像素总共发射 16 条光线 200x200x16
  • -[MyClassName copyWithZone:] 无法识别的选择器发送到实例

    我的应用程序崩溃了 原因是 MyClassName copyWithZone 无法识别的选择器发送到实例 我有两节课 假设 Class1 和 Class2 Class1 看起来像 Class1 h interface Class1 NSOb
  • “KMeans”对象没有属性“k”

    我使用 Yellowbrick 包绘制数据集的肘部曲线 以使用 KMeans 作为模型找到数据集的最佳簇数 我正在使用 Scikit learn KMeans 和 Yellowbrick kelbowvisualizer 函数 生成了肘部曲
  • 在字符串内打印单引号

    我想输出 XYZ s ABC 我在Python IDLE中尝试了以下3条语句 第一条和第二条语句输出 a before 带打印功能的第三条语句不输出 before 作为 Python 新手 我想了解为什么 之前输出 在第 1 条和第 2 条
  • 解析整数集的字符串并列出间隔

    I have 2 5 7 9 12 string 我想从中获取 2 5 7 8 9 12 列表 python中有没有内置的函数 Thanks UPD 我想 直接的答案是No 不管怎样 谢谢你的 片段 使用一个 建议者斯文 马尔纳克 s 2
  • 在 4K 屏幕上使用 Matplotlib 和 TKAgg 或 Qt5Agg 后端

    我在 Ubuntu 16 04 上使用 Matplotlib 2 0 和 Python 3 6 来创建数据图 电脑显示器的分辨率为 4k 分辨率为 3840x2160 绘图数字看起来非常小 字体也很小 我已经尝试过TKAgg and Qt5
  • 为什么我会在 Python 字符串格式中使用除 %r 之外的其他内容?

    我偶尔会使用 Python 字符串格式 这可以像这样完成 print int i Float f String s 54 34 434 some text 但是 这也可以这样做 print int r Float r String r 54
  • 将二进制数据视为文件对象?

    在此代码片段 由另一个人编写 中 self archive是一个大文件的路径并且raw file是以二进制数据形式读取的文件内容 with open self archive rb as f f seek offset raw file s
  • 如何使用 python 模块的多个 git 分支?

    我想使用 git 来同时处理我正在编写的模块中的多个功能 我目前正在使用 SVN 只有一个工作区 因此我的 PYTHONPATH 上只有该工作区 我意识到这不太理想 所以我想知道是否有人可以建议一种更 正确 的方法来做到这一点 让我用一个假
  • Django 中使用外键的抽象基类继承

    我正在尝试在 Django 支持的网站上进行模型继承 以遵守 DRY 我的目标是使用一个名为 BasicCompany 的抽象基类来为三个子类提供通用信息 Butcher Baker CandlestickMaker 它们位于各自的应用程序
  • 如何创建简单的梯度下降算法

    我正在研究简单的机器学习算法 从简单的梯度下降开始 但在尝试用 python 实现它时遇到了一些麻烦 这是我试图重现的示例 我获得了有关房屋的数据 居住面积 以英尺为单位 和卧室数量 以及最终的价格 居住面积 英尺2 2104 卧室 3 价
  • JSONDecodeError:额外数据:Python [重复]

    这个问题在这里已经有答案了 我使用以下代码从文件加载 json file file name obj list with open file as f for json obj in f obj list append loads json
  • 将二进制数转换为包含每个二进制数的数组

    我试图将二进制值转换为每个 1 0 的列表 但我得到默认的二进制值而不是列表 我有一个字符串 我将每个字符转换为二进制 它给了我一个列表 其中每个字符都有一个字符串 现在我试图将每个字符串拆分为值为 0 1 的整数 但我什么也得不到 if

随机推荐