【问题标题】:Constructor specialization in pythonpython中的构造函数专业化
【发布时间】:2009-07-29 20:06:15
【问题描述】:

类层次结构和构造函数是相关的。来自子类的参数需要传递给它们的父类。

所以,在 Python 中,我们最终会得到这样的结果:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        # do something with a, b, c, ka, kb, kc

class Child(Parent):
    def __init__(self, a, b, c, d, e, f, ka=None, kb=None, kc=None, kd=None, ke=None, kf=None):
        super(Child, self).__init__(a, b, c, ka=ka, kb=kb, kc=kc)
        # do something with d, e, f, kd, ke, kf

想象一下这有十几个子类和大量参数。添加新参数变得非常繁琐。

当然可以完全放弃命名参数而使用 *args 和 **kwargs,但这会使方法声明变得模棱两可。

在 Python (2.6) 中是否有优雅地处理这个问题的模式?

“优雅”是指我想减少参数出现的次数。 a、b、c、ka、kb、kc 均出现 3 次:在 Child 构造函数中、在对 Parent 的 super() 调用中以及在 Parent 构造函数中。

理想情况下,我想为 Parent 的 init 指定一次参数,而在 Child 的 init 中只指定附加参数。

我想做这样的事情:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        print 'Parent: ', a, b, c, ka, kb, kc

class Child(Parent):
    def __init__(self, d, e, f, kd='d', ke='e', kf='f', *args, **kwargs):
        super(Child, self).__init__(*args, **kwargs)
        print 'Child: ', d, e, f, kd, ke, kf

x = Child(1, 2, 3, 4, 5, 6, ka='a', kb='b', kc='c', kd='d', ke='e', kf='f')

不幸的是,这不起作用,因为 4、5、6 最终分配给了 kd、ke、kf。

是否有一些优雅的 python 模式可以完成上述操作?

【问题讨论】:

  • 您希望它如何工作?不知何故,我看不出更优雅的可能性在哪里。

标签: python design-patterns class oop anti-patterns


【解决方案1】:

“十几个子类和大量参数”听起来像是一个问题,与参数命名无关。

我怀疑稍微重构一下就可以剥离一些 Strategy 对象,从而简化这个层次结构并使超级复杂的构造函数消失。

【讨论】:

  • 我已经分解了一些策略对象,但是您的评论指出我阅读了一些阅读内容,这些阅读内容向我展示了如何简化我已经完成的工作。谢谢!
【解决方案2】:

嗯,我能看到的唯一解决方案是混合使用列出的变量以及 *args 和 **kwargs,例如:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        pass

class Child(Parent):
    def __init__(self, d, e, f, *args, kd=None, ke=None, kf=None, **kwargs):
        Parent.__init__(self, *args, **kwargs)
        pass

这样,您可以查看每个类需要哪些参数,而无需重新键入它们。

需要注意的一点是,您失去了所需的顺序(a、b、c、d、e、f),因为它变成了(d、e、f、a、b、c)。我不确定是否有办法将 *args 放在其他非命名参数之前。

【讨论】:

  • 这也是我的第一个想法,但 python 似乎要求 *args 和 **kwargs 放在最后,至少在 2.6 中。
  • 嗯,是的。我想当你迁移到 Python 3 时,将其锁定为其中一种可能性。
【解决方案3】:

我尝试将参数分组到它们自己的对象中,例如,而不是传递 sourceDirectory、targetDirectory、temporaryDirectory、serverName、serverPort,我有一个 DirectoryContext 和 ServerContext 对象。

如果上下文对象开始有更多 行为或逻辑可能导致here中提到的策略对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-14
    • 1970-01-01
    • 2015-03-12
    • 2016-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多