2

我试图在python中定义一个类B,A的子类,它可以接受多种实例化方式,非常灵活。A 是一个成员很少的简单类。我知道如何编写 A 以允许混合位置/关键字参数并在省略某些参数时使用默认值。

我的问题来自 B 类。B 只是 A 有一个额外的成员。但是当我创建 B 的一个实例时,我希望有以下选择:

  • 从位置/关键字参数混合创建的实例(非常像 A)
  • 创建指定额外成员的实例和 A 的现有实例(或副本)
  • 仅使用 A 的现有实例创建,并且额外成员获取默认值。
  • 互斥地使用 A 的现有实例和位置/关键字参数

编辑:像这样

class A:
    def __init__(self, x1=1, x2='a', x3=4.0)
        self.x1=x1
        self.x2=x2
        self.x3=x3

class B(A):
    def __init__(self, x1=1, x2='a', x3=4.0, x4='t')
        self.x4=x4
        A.__init__(x1,x2,x3)

但后来我想像这样使用它:

a1=A()
b1=B()         # takes all defaults
b2=B(x4='r')   # x1,x2,x3 gets defaults from A
b3=B(a1,x4='z')  # use a1, an instance of A
b4=B(x1,x2,x3,x4) # defines manually all arguments
b5=B(a1,x1=2) # this one should not work because x1 can come from the instance a1 or x1
4

2 回答 2

2

最简单的事情可能是使用B与使用相同的签名的简单直接的初始化器进行定义A,然后定义为类方法的附加工厂函数以执行更复杂的场景。这样,当两种不同的构造方法实际上采用完全无法区分的参数时,您就不会搞砸。

所以像:

class B(A):
    def __init__(self, some, args):
        A.__init__(self, some, args)

    @classmethod
    def fromA(cls, theA, extra=some_default):
        newB = cls(theA.some, theA.args)
        newB.extra = extra
        return newB
于 2012-10-29T13:36:41.660 回答
0

根据我的经验,处理此类复杂情况的最佳方法是*args, **kwargs通过一系列条件手动使用和处理它们,例如B.__init__

if isinstance(arg[0], A):
    if has_other_args:
        raise TypeError
    else:
        do_something()
else:
    do_something_else()

但是,这仍然会变得非常复杂,因此工厂函数(如 Duncan 所建议的)可能是最好的方法。

旁注:每当我发现自己需要这种功能时,这通常表明我的设计有问题。即使我实现了它,我通常最终也会用更整洁的东西替换整个结构。

于 2012-10-29T13:41:29.433 回答