我有一个有很多直接子类的基类。多个子类共享多个独立功能。这是Python的合作继承的一个很好的用例。但是,这些功能应该从外部包装行为,因此它们需要在方法解析顺序中更早。
func rotate(duration: CFTimeInterval = 1.0, degrees:Double, completionDelegate: AnyObject? = nil) {
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotateAnimation.fromValue = 0.0
let radians = CGFloat(degrees * M_PI / degrees)
rotateAnimation.toValue = CGFloat(radians)
rotateAnimation.duration = duration
if let delegate: AnyObject = completionDelegate {
rotateAnimation.delegate = delegate
}
self.layer.addAnimation(rotateAnimation, forKey: nil)
// Actually set the layer's property
self.layer.transform = CATransform3DMakeRotation(radians, 0.0, 0.0, 1.0)
}
最好装饰子类。
class WrappedSub(FeatureA, FeatureB, FeatureC, RealSub):
def __init__(self, *args, **kwargs):
FeatureA.__init__(foo=42)
FeatureB.__init__(bar=13)
FeatureC.__init__(foobar=546)
RealSub.__init__(*args, **kwargs)
class RealSub(Base):
# Lots of code ...
准确地说,我需要一个@Mixin(FeatureA, 42)
@Mixin(FeatureB, 13)
@Mixin(FeatureC, 546)
class RealSub(Base):
# Lots of code ...
装饰器,其中下面的第一个块等同于第二个。
@Mixin
在Python 3中这怎么可能?
答案 0 :(得分:3)
您可以使用Python的协作多继承系统来编写mixin类,而不是尝试将它们实现为类装饰器。这就是我通常理解在Python OOP中使用的术语“mixin”。
class Base:
def method(self, param):
value = param + 18
return value
class FeatureOne: # this could inherit from Base
def method(self, param):
if param == 42:
return 13
else:
return super().method(param) # call next class in inheritance chain
class Child(FeatureOne, Base):
def method(self, param):
value = super().method(param)
value *= 2
return value
这与您想要的不完全相同,因为它在FeatureOne
和method
类版本之间调用Base
类的Child
实现,而不是在Child
做之前。您可以改为添加一个新的Grandchild
类,它继承自您首先关注的Feature
,而Child
最后一个,如果您无法调整方法以按此顺序工作( Grandchild
班的身体可能是空的。)
如果你真的想使用装饰器来翻转顺序,我认为你可以使它工作,装饰器为你构建一个“孙子”类(尽管它对正常的继承层次结构一无所知) 。这是对mixin
装饰器的粗略尝试,它几乎可以像你想要的那样工作:
def mixin(*mixin_classes, **mixin_kwargs): # decorator factory function
def decorator(cls): # decorator function
class wrapper(*mixin_classes, cls):
def __init__(self, *args, **kwargs):
wrapped_kwargs = mixin_kwargs.copy() # use the passed kwargs to update the
wrapped_kwargs.update(kwargs) # mixin args, so caller can override
super().__init__(*args, **wrapped_kwargs)
# maybe modify wrapper's __name__, __qualname__, __doc__, etc. to match cls here?
return wrapper
return decorator
mixin类应该从他们自己的super().__init__(*args, **kwargs)
方法调用__init__
(如果有的话),但他们可以接受(而不是传递)他们想要的自己的关键字参数由mixin
装饰者传递:
class FeatureOne:
def __init__(self, *args, foo, **kwargs): # note that foo is a keyword-only argument
self.foo = foo
super().__init__(*args, **kwargs)
def method(self, param):
if param == self.foo:
return 13
else:
return super().__method__(param)
@mixin(FeatureOne, foo=42)
class Child(Base):
def method(self, param):
return super().method(param) * 2
装饰器应该与传递给一个装饰器调用的所有mixin类(例如@mixin(FeatureA, FeatureB, FeatureC, foo=42, bar=13, foobar=546)
)或几个嵌套的装饰器调用一起工作。最终班级的MRO将采用相同的方式。