在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
我尝试使用元类,但是为所有子类(C
,A
设置了B
(到D
或E
)的基类, ...)在第一个子类的初始化。因此,如果要初始化的第一个子类具有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
类的附加功能。我应该提一下,我无法控制A
和B
类。
我想我用这个元类得到了它(代码目前有点粗糙):
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)
这个解决方案不起作用,因为我总是修改基类C.因此,当子类被实例化时,它将在其当前状态中使用C类。
答案 0 :(得分:1)
我最后使用cooperative multiple inheritance。它工作正常。唯一的缺点是我们需要确保对于需要在许多父类上调用的方法(如A
和B
和C
中存在的方法),有一个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_method
或C
个孩子的C
来电时,所有这些电话都将按此顺序进行:
检查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