dan*_*jar 3 inheritance decorator mixins python-3.x python-decorators
我有一个基类,它有很多直接子类。有多个独立的特征由多个子类共享。这是 Python 合作继承的一个很好的用例。但是,这些功能应该从外部包装行为,因此它们需要位于方法解析顺序的前面。
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 ...
Run Code Online (Sandbox Code Playgroud)
如果能装饰一下子类就好了。
@Mixin(FeatureA, 42)
@Mixin(FeatureB, 13)
@Mixin(FeatureC, 546)
class RealSub(Base):
# Lots of code ...
Run Code Online (Sandbox Code Playgroud)
准确地说,我需要一个@Mixin装饰器,其中下面的第一个块相当于第二个块。
@Mixin(Sub, *feature_args, **feature_kwargs)
class RealSub:
# Lots of code ...
class RealSub:
# Lots of code ...
class WrappedSub(Feature, RealSub):
def __init__(self, *sub_args, **sub_kwargs):
Feature.__init__(self, *feature_args, **feature_kwargs)
RealSub.__init__(self, *sub_args, **sub_kwargs)
RealSub = WrappedSub
Run Code Online (Sandbox Code Playgroud)
这在 Python 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
Run Code Online (Sandbox Code Playgroud)
这与您想要的不太一样,因为它在和类的版本之间调用FeatureOne类的method实现,而不是在其执行之前调用。如果您无法调整方法以按此顺序工作(类的主体可能为空) ,您可以添加一个继承自您首先关心的 s 和最后一个的新类。BaseChildChildGrandchildFeatureChildGrandchild
如果你真的想使用装饰器来翻转顺序,我想你可能可以让它工作,装饰器为你构建一个“孙子”类(尽管它不知道任何关于正常继承层次结构的信息)。这是一个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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
装饰器应该与传递给一个装饰器调用的所有 mixin 类一起工作(例如@mixin(FeatureA, FeatureB, FeatureC, foo=42, bar=13, foobar=546)),或者与多个嵌套装饰器调用一起工作。无论哪种方式,最终课程的 MRO 都是相同的。
| 归档时间: |
|
| 查看次数: |
1546 次 |
| 最近记录: |