如何应用“mixin”类到旧式基类

发布于 2024-09-16 10:56:18 字数 853 浏览 10 评论 0原文

我编写了一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

烟雨凡馨 2024-09-23 10:56:18

该类变量将通过以下方式设置
old_style_mix 作为混合的一部分
流程。

...我假设您的意思是:“...在它正在装饰的类上...”而不是“在作为其参数的类上”(后者将是一场灾难)。

old_style_mix只会更新
例如的类字典
MixedWithOldStyleClass 与
mixin 类的内容(例如
MixinOldSchoolRemix) 字典。

不好——例如,MixinOldSchoolRemixMixinClass 派生的信息不在在前者的字典中。因此,old_style_mix 必须采取不同的策略:例如,构建一个新类(我认为它必须是新式类,因为旧式类不会接受新样式的 __bases__),具有适当的碱基序列以及适当调整的字典。

这是一个合理的策略吗?

有了上述条件。

这似乎是一个常见的现象
问题,考虑到有很多
仍在使用的可用模块
旧式课程。

...但是从未设计为采用 mixin 的类的 mixin 绝对不是常见的设计模式,因此这个问题根本不常见(我什至不记得在自从新式课程诞生以来很多年了,这些年来我一直在积极咨询、教授高级课程、帮助人们解决 Python 问题,以及自己进行大量软件开发——我确实经常遇到人们可能会遇到的任何“相当常见”的问题,这些问题已经存在了足够长的时间!-)。

以下是类装饰器可以执行的操作的示例代码(如果您更喜欢将其放在类装饰器中而不是直接内联...):

>>> class Mixo(object):
...   def foo(self):
...     print 'Mixo.foo'
...     self.thesuper.foo(self)
... 
>>> class Old:
...   def foo(self):
...     print 'Old.foo'
... 
>>> class Mixed(Mixo, Old):
...   thesuper = Old
... 
>>> m = Mixed()
>>> m.foo()
Mixo.foo
Old.foo

如果您想在假定的名称/绑定下构建 Mixed在装饰器中使用 Mixo ,您可以通过调用 type 或通过设置 Mixed.__name__ = cls.__name__ (其中 >cls 是您正在装饰的类)。我认为后一种方法更简单(警告,未经测试的代码——上面的交互式 shell 会话是真实的,但我还没有测试以下代码):

def oldstylemix(mixin):
    def makemix(cls):
        class Mixed(mixin, cls):
            thesuper = cls
        Mixed.__name__ = cls.__name__
        return Mixed
    return makemix

This class variable would be set by
old_style_mix as part of the mixing
process.

...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).

old_style_mix would just update the
class dictionary of e.g.
MixedWithOldStyleClass with the
contents of the mixin class (e.g.
MixinOldSchoolRemix) dictionary.

No good -- the information that MixinOldSchoolRemix derives from MixinClass, 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.

Is this a reasonable strategy?

With the above provisos.

It seems like this would be a common
problem, given that there are numerous
available modules still using
old-style classes.

...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...):

>>> class Mixo(object):
...   def foo(self):
...     print 'Mixo.foo'
...     self.thesuper.foo(self)
... 
>>> class Old:
...   def foo(self):
...     print 'Old.foo'
... 
>>> class Mixed(Mixo, Old):
...   thesuper = Old
... 
>>> m = Mixed()
>>> m.foo()
Mixo.foo
Old.foo

If you want to build Mixed under the assumed name/binding of Mixo in your decorator, you could do it with a call to type, or by setting Mixed.__name__ = cls.__name__ (where cls 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):

def oldstylemix(mixin):
    def makemix(cls):
        class Mixed(mixin, cls):
            thesuper = cls
        Mixed.__name__ = cls.__name__
        return Mixed
    return makemix
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文