如何应用“mixin”类到旧式基类
我编写了一个 mixin 类,它被设计为分层在新式类之上,例如通过
class MixedClass(MixinClass, BaseClass):
pass
What's the smoothest way to apply this mixin to an old-style class?它在其 __init__
方法中使用对 super
的调用,因此这可能(?)必须更改,但否则我想尽可能少地进行更改到 MixinClass。我应该能够派生一个进行必要更改的子类。
我正在考虑在从 BaseClass
派生的类之上使用类装饰器,例如
@old_style_mix(MixinOldSchoolRemix)
class MixedWithOldStyleClass(OldStyleClass)
,其中 MixinOldSchoolRemix
派生自 MixinClass
并且只是重新实现使用 super
来代替使用包含与其混合的类的类变量的方法,在本例中为 OldStyleClass
。作为混合过程的一部分,该类变量将由old_style_mix 设置。
old_style_mix
只会使用 mixin 类(例如 MixinOldSchoolRemix
)字典的内容更新例如 MixedWithOldStyleClass
的类字典。
这是一个合理的策略吗?有更好的办法吗?鉴于有许多可用模块仍在使用旧式类,这似乎是一个常见问题。
I've written a mixin class that's designed to be layered on top of a new-style class, for example via
class MixedClass(MixinClass, BaseClass):
pass
What's the smoothest way to apply this mixin to an old-style class? It is using a call to super
in its __init__
method, so this will presumably (?) have to change, but otherwise I'd like to make as few changes as possible to MixinClass
. I should be able to derive a subclass that makes the necessary changes.
I'm considering using a class decorator on top of a class derived from BaseClass
, e.g.
@old_style_mix(MixinOldSchoolRemix)
class MixedWithOldStyleClass(OldStyleClass)
where MixinOldSchoolRemix
is derived from MixinClass
and just re-implements methods that use super
to instead use a class variable that contains the class it is mixed with, in this case OldStyleClass
. This class variable would be set by old_style_mix
as part of the mixing process.
old_style_mix
would just update the class dictionary of e.g. MixedWithOldStyleClass
with the contents of the mixin class (e.g. MixinOldSchoolRemix
) dictionary.
Is this a reasonable strategy? Is there a better way? It seems like this would be a common problem, given that there are numerous available modules still using old-style classes.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
...我假设您的意思是:“...在它正在装饰的类上...”而不是“在作为其参数的类上”(后者将是一场灾难)。
不好——例如,
MixinOldSchoolRemix
从MixinClass
派生的信息不在在前者的字典中。因此,old_style_mix
必须采取不同的策略:例如,构建一个新类(我认为它必须是新式类,因为旧式类不会接受新样式的__bases__
),具有适当的碱基序列以及适当调整的字典。有了上述条件。
...但是从未设计为采用 mixin 的类的 mixin 绝对不是常见的设计模式,因此这个问题根本不常见(我什至不记得在自从新式课程诞生以来很多年了,这些年来我一直在积极咨询、教授高级课程、帮助人们解决 Python 问题,以及自己进行大量软件开发——我确实经常遇到人们可能会遇到的任何“相当常见”的问题,这些问题已经存在了足够长的时间!-)。
以下是类装饰器可以执行的操作的示例代码(如果您更喜欢将其放在类装饰器中而不是直接内联...):
如果您想在假定的名称/绑定下构建
Mixed
在装饰器中使用Mixo
,您可以通过调用type
或通过设置Mixed.__name__ = cls.__name__
(其中>cls
是您正在装饰的类)。我认为后一种方法更简单(警告,未经测试的代码——上面的交互式 shell 会话是真实的,但我还没有测试以下代码):...I assume you mean: "...on the class it's decorating..." as opposed to "on the class that is its argument" (the latter would be a disaster).
No good -- the information that
MixinOldSchoolRemix
derives fromMixinClass
, for example, is not in the former's dictionary. So,old_style_mix
must take a different strategy: for example, build a new class (which I believe has to be a new-style one, because old-style ones do not accept new-style ones as__bases__
) with the appropriate sequence of bases, as well as a suitably tweaked dictionary.With the above provisos.
...but mixins with classes that were never designed to take mixins are definitely not a common design pattern, so the problem isn't common at all (I don't remember seeing it even once in the many years since new-style classes were born, and I was actively consulting, teaching advanced classes, and helping people with Python problems for many of those years, as well as doing a lot of software development myself -- I do tend to have encountered any "reasonably common" problem that people may have with features which have been around long enough!-).
Here's example code for what your class decorator could do (if you prefer to have it in a class decorator rather than directly inline...):
If you want to build
Mixed
under the assumed name/binding ofMixo
in your decorator, you could do it with a call totype
, or by settingMixed.__name__ = cls.__name__
(wherecls
is the class you're decorating). I think the latter approach is simpler (warning, untested code -- the above interactive shell session is a real one, but I have not tested the following code):