基本上,我想要的是这样做:
class B:
def fn(self):
print 'B'
class A:
def fn(self):
print 'A'
@extendInherit
class C(A,B):
pass
c=C()
c.fn()
输出为
A
B
我如何实现extendInherit装饰器?
答案 0 :(得分:4)
这不是装饰者的工作。您希望完全更改类的正常行为,因此这实际上是元类的工作。
import types
class CallAll(type):
""" MetaClass that adds methods to call all superclass implementations """
def __new__(meta, clsname, bases, attrs):
## collect a list of functions defined on superclasses
funcs = {}
for base in bases:
for name, val in vars(base).iteritems():
if type(val) is types.FunctionType:
if name in funcs:
funcs[name].append( val )
else:
funcs[name] = [val]
## now we have all methods, so decorate each of them
for name in funcs:
def caller(self, *args,**kwargs):
""" calls all baseclass implementations """
for func in funcs[name]:
func(self, *args,**kwargs)
attrs[name] = caller
return type.__new__(meta, clsname, bases, attrs)
class B:
def fn(self):
print 'B'
class A:
def fn(self):
print 'A'
class C(A,B, object):
__metaclass__=CallAll
c=C()
c.fn()
答案 1 :(得分:1)
我个人不会尝试使用装饰器,因为使用新式类和super()
,可以实现以下目的:
>>> class A(object):
... def __init__(self):
... super(A, self).__init__()
... print "A"
...
>>> class B(object):
... def __init__(self):
... super(B, self).__init__()
... print "B"
...
>>> class C(A, B):
... def __init__(self):
... super(C, self).__init__()
...
>>> foo = C()
B
A
我想方法调用会以同样的方式工作。
答案 2 :(得分:1)
元类是一种可能的解决方案,但有些复杂。 super
可以非常简单地做到(当然有新的样式类:没有理由在新代码中使用遗留类!):
class B(object):
def fn(self):
print 'B'
try: super(B, self).fn()
except AttributeError: pass
class A(object):
def fn(self):
print 'A'
try: super(A, self).fn()
except AttributeError: pass
class C(A, B): pass
c = C()
c.fn()
你需要try / except来支持单个或多个继承的任何顺序(因为在某些时候,方法解析顺序MRO没有进一步的基础,定义一个名为fn
的方法,你需要捕获并忽略生成的AttributeError
)。但是正如您所看到的,与您根据对不同答案的评论所看到的不同,您不一定需要覆盖最底层的fn
,除非您需要在此类中执行特定于该类的操作。覆盖 - super
也适用于纯粹继承(未覆盖)的方法!