【问题标题】:How can I return a value to a superclass without overriding the parent function?如何在不覆盖父函数的情况下将值返回给超类?
【发布时间】:2016-09-19 16:21:11
【问题描述】:

我想定义一个与其父级同名的函数,它返回一个父级可以接收和使用的值。虽然我认为可以通过元类来实现这一点,但我不确定如何做到这一点(假设有可能)以及是否有更好、更清洁的解决方案。

我想要的格式如下所示。 Child 类将由我以外的开发人员定义,所以我希望尽可能少的限制。 (例如,理想情况下,我不希望使用 super(Child).f(a) 替换 return a。)我也不确定如何在我的模型中使用关键字参数,这会更好。

class Parent:
    def f(self, arg):
        print("Received {}.".format(arg))
        return arg ** 3

class Child(Parent):
    def f(self, c, b, a):
        print(a, b, c)
        return a

# Prints "2 1 0" and "Received 2.". Sets value to 8.
value = Child().f(0, 1, 2)

【问题讨论】:

  • 在 python 2.7 和 3.4 上打印 2 1 0
  • 如果你在一个同名的子类中定义了一个方法,那么根据定义你覆盖了父方法。我很确定你想做的事情是不可能的,而且无论如何都是个坏主意。我建议您在父级中有f 调用一些抽象方法g,子级负责覆盖。
  • 请注意,它只是return super().f(a)

标签: python python-3.x inheritance python-3.5 metaclass


【解决方案1】:

这句话有一个关键问题:

我想定义一个与它的父级同名的函数,它返回一个父级可以接收的值

请问,为什么需要这样做?

Child 类中的 f 与 Parent 类中的 f 完全不同,因此将它们命名为相同的东西会非常令人困惑,即使您确实可以使用它。

假设我使用您的Parent 编写了子类:

class Child(Parent):
    def f(self):
        return 2

我希望 Child().f() 返回 2,但如果您在幕后添加隐藏逻辑以添加 arg ** 3,那么我将得到 8 并且完全混淆并诅咒您的库添加非常不直观的规则。


为什么不使用一个函数并在子类中定义额外的逻辑辅助函数:

class Parent:
    def f(self, *v_args):
        arg = self.helper_f(*v_args)
        print("Received {}.".format(arg))
        return arg ** 3

    def helper_f(self,*args):
        "really should be an abstract method, must be implemented in a subclass"
        raise NotImplementedError("Must override in a subclass!") 

class Child(Parent):
    def helper_f(self, c, b, a):
        print(a, b, c)
        return a

# Prints "Received 2.". Sets value to 8.
value = Child().f(0, 1, 2)

当然,是的,从技术上讲,您可以使用元类自动执行此操作。但是,对于使用您的 Parent 类的任何人来说,这都会完全混淆

class Child_Method_Redirector(type):
    def __new__(meta, name, bases, cls_dict):
        if bases is not ():
            if "f" in cls_dict:
                cls_dict["_auto_renamed_helper_f"] = cls_dict["f"]
                del cls_dict["f"]
        return type.__new__(meta,name,bases,cls_dict)


class Parent(metaclass=Child_Method_Redirector):
    def f(self, *v_args):
        arg = self._auto_renamed_helper_f(*v_args)
        print("Received {}.".format(arg))
        return arg ** 3

class Child(Parent):
    def f(self):
        return 2

# now it does Print "Received 2." and Sets value to 8.
value = Child().f()

但是请不要这样做,这违反了the zen

显式优于隐式。
应该有一种——最好只有一种——明显的方法。
如果实现难以解释,那就是个坏主意。

【讨论】:

  • 作为旁注,我想指出“可以实现在 <...> curcumstances 下调用的特殊方法”是相当普遍的约定,想想dict 子类覆盖__missing__
猜你喜欢
  • 2017-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-18
相关资源
最近更新 更多