初始化类但在python中使用不同的父级

时间:2011-03-22 03:26:06

标签: python

在python中,有没有办法在初始化一个Class时,根据类属性的值来改变超类?这是我想要做的一个例子。首先,我有这些课程:

class A(object):
    pass

class B(A):
    # extend and override class A
    pass

class C(A or B):
    # extend and override class A
    pass

其次,我想创建继承自Class C的其他类,但在某些情况下我希望C继承自A,而在其他情况下,继承自B:

class D(C):
    # C inherit only from A
    from_B = False

class E(C):
    # C inherit from B because attribute from_B = True
    from_B = True

我尝试使用元类,但是为所有子类(CA设置了B(到DE)的基类, ...)在第一个子类的初始化。因此,如果要初始化的第一个子类具有from_B = True,则C的所有子类都将C(B)作为父级from_B设置。我的代码是这样的:

class MetaC(type):
    def __new__(cls, name, bases, attrs):
        if C in bases and getattr(attrs, 'from_B', False):
            C.__bases__[C.__bases__.index(A)] = B
        return super(MetaC, cls).__new__(cls, name, bases, attrs)

class C(A):
    __metaclass__ = MetaC

我的目标是避免重复C类的代码,并保留是否有B类的附加功能。我应该提一下,我无法控制AB类。

更新

我想我用这个元类得到了它(代码目前有点粗糙):

class MetaC(type):
    def __new__(cls, name, bases, attrs):
        for base in bases:
            if base.__name__ == 'C':
                if attrs.has_key('from_B'):
                    list_bases = list(base.__bases__)
                    list_bases[list_bases.index(A)] = B
                    base.__bases__ = tuple(list_bases)
                elif B in base.__bases__:
                    list_bases = list(base.__bases__)
                    list_bases[list_bases.index(B)] = A
                    base.__bases__ = tuple(list_bases)
                break
        return super(MetaC, cls).__new__(cls, name, bases, attrs)

更新2

这个解决方案不起作用,因为我总是修改基类C.因此,当子类被实例化时,它将在其当前状态中使用C类。

2 个答案:

答案 0 :(得分:1)

我最后使用cooperative multiple inheritance。它工作正常。唯一的缺点是我们需要确保对于需要在许多父类上调用的方法(如ABC中存在的方法),有一个super()调用每个类的每个方法定义,并且在每种情况下它们都具有相同的调用签名。幸运的是,我的B课程尊重这一点。

示例:

class A(object):
    some_method(arg1, arg2, karg1=None):
        do_some_stuff(arg1, arg2, karg1)

class B(A):
    # extend and override class A
    some_method(arg1, arg2, karg1=None):
        super(B, self).some_method(arg1, arg2, karg1)
        do_more_stuff(arg1, arg2, karg1)

class C(A, B):
    # extend and override class A
    some_method(arg1, arg2, karg1=None):
        do_other_stuff(arg1, arg2, karg1)
        super(C, self).some_method(arg1, arg2, karg1)

这样,当来自some_methodC个孩子的C来电时,所有这些电话都将按此顺序进行:

  • C.some_method
  • A.some_method
  • B.some_method

检查The wonders of cooperative inheritance以获取有关该主题的更多信息。

答案 1 :(得分:0)

这看起来很痛苦,你必须考虑组合/委托而不是以这种方式扭曲继承。你怎么看待这样的事情?

class A(object):
    def from_B(self):
        return False

class B(object):
    def from_B(self):
        return True

class C(object):
    pass


class PolyClass(object):
    def __init__(self, *args):
        self.delegates = [c() for c in args[::-1]]

    def __getattr__(self, attr):
        for d in self.delegates:
            if hasattr(d, attr):
                return getattr(d,attr)
        raise AttributeError(attr + "? what the heck is that?")

    def __repr__(self):
        return "<instance of (%s)>" % ','.join(d.__class__.__name__ 
                                    for d in self.delegates[::-1])

pc1 = PolyClass(A,B)
pc2 = PolyClass(A,C)
pc3 = PolyClass(B,C)

for p in (pc1,pc2,pc3):
    print p, p.from_B()

print pc1.from_C()

打印:

<instance of (A,B)> True
<instance of (A,C)> False
<instance of (B,C)> True
Traceback (most recent call last):
  File "varying_delegation.py", line 33, in <module>
    print pc1.from_C()
  File "varying_delegation.py", line 21, in __getattr__
    raise AttributeError(attr + "? what the heck is that?")
AttributeError: from_C? what the heck is that?

编辑: 以下是如何使用非控制类A和B,并创建看起来像的自定义C类,它们扩展为A或B:

# Django admin classes
class A(object):
    def from_B(self):
        return False

class B(A):
    def from_B(self):
        return True

# Your own class, which might get created with an A or B instance
class C(object):
    def __init__(self, obj):
        self.obj = obj

    def __getattr__(self, attr):
        return getattr(self.obj, attr)

# these are instantiated some way, not in your control
a,b = A(), B()

# now create different C's
c1 = C(a)
c2 = C(b)

print c1.from_B()
print c2.from_B()

打印:

False
True

要创建你的子类D和E,创建一个C的临时子类(我称之为SubC,因为我缺乏想象力),它将使用特定的全局变量a或b自动初始化C超类。

# a subclass of C for subclasses pre-wired to delegate to a specific 
# global object
class SubC(C):
    c_init_obj = None
    def __init__(self):
        super(SubC,self).__init__(self.c_init_obj)

class D(SubC): pass
class E(SubC): pass

# assign globals to C subclasses so they build with the correct contained 
# global object
D.c_init_obj = a
E.c_init_obj = b
d = D()
e = E()
print d.from_B()
print e.from_B()

再次,打印:

False
True