Python 处理冗余函数参数的正确方法

Python 处理冗余函数参数的正确方法,python,inheritance,Python,Inheritance,假设以下类层次结构具有基类和从基类继承的某些常规案例类: class BaseClass: def f(self, a, b): #do something pass class GeneralCase(BaseClass): def f(self, a, b): BaseClass.f(self, a, b) #do something else 现在,假设我们有一个特殊的情况,其中函数f的一个参数是预先确定的

假设以下类层次结构具有基类和从基类继承的某些常规案例类:

class BaseClass:
    def f(self, a, b):
        #do something
        pass

class GeneralCase(BaseClass):
    def f(self, a, b):
        BaseClass.f(self, a, b)
        #do something else
现在,假设我们有一个特殊的情况,其中函数
f
的一个参数是预先确定的且恒定的。一个 实现这一点的方法是从参数列表中删除此参数,如下所示:

class SpecialCase1(GeneralCase):
    def f(self, a):
专业人士:干净、明确

缺点:当使用不同类的对象时,不同的方法签名可能会导致问题

选项2:设置默认值并断言它不会更改

class SpecialCase2(GeneralCase):
    def f(self, a, b=PREDEFINED_VALUE):
        assert b == PREDEFINED_VALUE
        GeneralCase.f(self, a, PREDEFINED_VALUE)
赞成者:同样的签名

Con's:令人困惑的界面:“为什么我们有参数b?如果我改变它会发生什么?”


你会选择什么方法?为什么?

它根本不应该是一个子类型(参见Liskov替换原则)

GeneralCase
有一个属性,即:

有一种方法
f
有两个参数。。。雅达雅达雅达是哪个

此属性应适用于
GeneralCase
的所有子类型(或duck-typed,任何像
GeneralCase
一样嘎嘎作响的类型,无论类关系如何)。如果它不起作用,所有处理此类对象的代码都必须知道它和它周围的代码。这是一个不可接受的负担,而且基本上是不必要的

如果该属性对于某些特殊情况不成立,则该特殊情况不应是子类型。它可能是高度相关的,但要么您需要一个更通用的
GeneralCase
,要么它不是
GeneralCase
的特例

如果希望代码重用,请使用mixin。如果有代码可以在
GeneralCase
SpecialCase
上运行(例如,因为它不使用该方法),您可以定义一个不包含该方法的更通用的接口(可能是隐式的,我们不需要
接口
关键字)从而避免了上述问题。

那么:

class SpecialCase2(GeneralCase):
    def f(self, a, b):
        GeneralCase.f(self, a, PREDEFINED_VALUE)

这样,特例2根本不使用b,接口保持不变。

有第三个选项:使
get_b
成为一个方法,让子类覆盖它,所以您不需要将它作为参数传递。这是一个输入错误吗assert p==预定义的_值,应该是assert b=预定义的_值?这两种方法都很糟糕。它根本不应该是一个子类型。如果你检查这个值,你就不会遇到与第一个解决方案相同的问题(甚至是最糟糕的问题)?@bg:当然。参见Liskov替换原理。
GeneralCase
及其子类的属性“有一个方法
f
有两个参数…它不需要yadda yadda yadda”,对于您的特殊情况不适用。如果对某些特殊情况不是这样,那么该特殊情况不应该是子类型。如果你想重用代码,可以使用mixin或者其他东西。实际上这是一个非常糟糕的解决方案。如果用户有可能向函数传递参数,他们有权假定参数会影响函数行为。然后使用新签名覆盖函数,但有些人不喜欢此解决方案(见上文)