【问题标题】:How to customize the method resolution order (mro) of Python?如何自定义 Python 的方法解析顺序(mro)?
【发布时间】:2020-09-15 05:52:26
【问题描述】:

我想自定义调用我继承的方法。

这是一个示例代码:

class First(object):
    def get(self):
        print('getting from first')

    def set(self):
        print('setting to first')

class Second(object):
    def get(self):
        print('getting from second')

    def set(self):
        print('setting to second')

class Third(First, Second):
    def get(self):
        super(Third, self).get()

    def set(self):
        super(Third, self).set()

现在我想要的行为是这样的:

third = Third()
third.get() # -> should print 'getting from first'
third.set() # -> should print 'setting to second'

现在 mro 显示:

Third.__mro__ ->  (__main__.Third, __main__.First, __main__.Second, object)

我们可以看到 ma​​in.First 中的方法总是首先被调用。虽然我想要的是 ma​​in.Second 在执行 set() 方法期间首先被调用。

这是我解决这个问题的尝试,尝试修改 Third 类的 MRO

思路是把两个类的两个位置互换一下,看看能不能行。 首先,一个swap() 辅助函数。

def swap(index1, index2, mro_tuple):
    l = list(mro_tuple)
    temp = l[index1]
    l[index1] = l[index2]
    l[index2] = temp
    return tuple(l)

然后在set()方法的实现过程中,我尝试修改底层类的mro

class Third(First, Second):
    def get(self):
        super(Third, self).get()
    def set(self):
        self.__class__.__mro__ = swap(1, 2, self.__class__.__mro__) # swap here..
        super(Third, self).set() # then call method**
In [43]: third = Third() 

In [44]: third.get()                                                            
getting from first

In [45]: third.set()                                                            
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-53-c82ac1a0d5bc> in <module>
----> 1 third.set()

<ipython-input-50-00c9baff0d57> in set(self)
      4 
      5     def set(self):
----> 6         self.__class__.__mro__ = swap(1, 2, self.__class__.__mro__) # swap here..
      7         super(Third, self).set() # then call method
      8 

AttributeError: readonly attribute

说明__mro__属性无法重置。

有没有办法以一种方便的方式实现这种行为?

【问题讨论】:

    标签: python multiple-inheritance method-resolution-order


    【解决方案1】:

    您最好的选择可能是让Third 明确使用Second 实现:

    class Third(First, Second):
        set = Second.set
    

    尽管您提出这个问题是一个警告信号,表明您可能选择了错误的类层次结构。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-20
      • 2010-12-23
      • 2020-09-10
      • 2021-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多