继承子类MRO的别名

时间:2018-03-23 22:59:04

标签: python

class parent:
    def fun1(self):
        print("foo")

    fun2 = fun1

class child(parent):
    def fun1(self):
        print("bar")

child().fun2()

此代码输出" foo"。我很确定我理解为什么会这样,但我想知道是否有一种直接的方式来实现我想要的东西(根据MRO行为的可继承别名,所以它输出" bar&# 34;)或者这是一个错误的编程实践的原因。

3 个答案:

答案 0 :(得分:3)

没有办法直接做你想做的事。

要了解原因,您需要了解方法查找的工作方式。我在the Descriptor HOWTO中对此进行了详细解释,并尝试编写一个不太专家级别的解释here,因此我假设您已经阅读了这两个解释并只显示了这些效果:

>>> child.fun1
<function __main__.child.fun1>
>>> child.fun2
<function __main__.parent.fun1>
>>> child().fun2
<bound method parent.fun1 of <__main__.child object at 0x10b735ba8>>

请注意child.fun2parent.fun1,而不是child.fun1。这解释了为什么child().fun2最终成为parent.fun1的绑定方法,即使self最终为child个实例。为什么?好吧,显然fun2不在child.__dict__中(或者我们不需要MRO)。在parent.__dict__中,它不能是parent.fun1

那么,有哪些解决方法?

正如Patrick Haugh建议的那样,您可以将fun2变为property转发到fun2。或者你可以这样做:

def fun2(self):
    return self.fun1()

这个解决方案有一个简单的好处 - 任何能够使用Python的人都能理解它的工作原理。

但帕特里克的解决方案的优点是不仅可以child().fun2(),还可以child().fun2(作为一个可以传递的对象,比较身份等等)的工作方式就像你一样想要它。

与此同时,有一个与你所要求的内容密切相关的习惯用语,你不希望覆盖的一套公共方法称为“受保护的”#34;&#34;你做的实现方法。例如,一个简单的1D数组数学类可能会这样做:

def _math(lhs, rhs, op):
    # not actually a useful implementation...
    return [op(x, y) for x, y in zip(lhs, rhs)] 
def __add__(self, other):
    return self._math(other, add)
def __radd__(self, other):
    return self._math(other, add)
# etc.

现在__add____radd__之间没有不对称,只有公共&#34;界面(__add____radd__)和&#34;受保护的&#34;一个(_math)。

答案 1 :(得分:2)

这是一种非常直接的方式 - 完全可以:

class Parent:
    def fun1(self):
        print("foo")

    def fun2(self):
        return self.fun1()


class Child(Parent):
    def fun1(self):
        print("bar")


Child().fun2()  # -> bar

答案 2 :(得分:1)

您可以将fun2作为返回self.fun1

的属性
class Parent:
    def fun1(self):
        print('foo')
    @property
    def fun2(self):
        return self.fun1

class Child(Parent):
    def fun1(self):
        print('bar')

Child().fun2()
# bar