Alex Martelli wrote: > What's DebugFrameworkMeta2? I assume it's some kind of mix but I > don't see it defined anywhere so I'm having to guess.
Sorry Alex, here is definition which got lost in cut&paste: DebugFrameworkMeta2 = include_mixin(DebugMeta2, FrameworkMeta2) > I'd like to understand what, in this example, removes the apparent > "fragility" (or, lack of flexibility) where DebugMeta2 specifically > uses mcl.__base__ -- IOW, if I have another "mixin metaclass" just > like DebugMeta2 but called (say) RemotableMeta which does a print > "Adding remoting features" and then also calls > mcl.__base__.__new__(mcl ... just like DebugMeta2, what gets both of > their __new__ methods called in the right order? If you want to reimplement full cooperation between mixins classes you must rework a bit the example, but it does not take a big effort (see later). However my main point is: do we really want cooperative methods? Multiple inheritance of metaclasses is perhaps the strongest use case for multiple inheritance, but is it strong enough? I mean, in real code how many times did I need that? I would not mind make life harder for gurus and simpler for application programmers. I do not think removing cooperation would be so bad in practice. In many practical cases, one could just write the metaclass by hand, in this example something like class RemotableDebugFrameworkMeta(FrameworkMeta): def __new__(mcl, name, bases, dic): print "Adding remoting features to %s" % name print "Adding debugging features to %s" % name return FrameworkMeta.__new__(mcl, name, bases, dic) Maybe you would need to duplicate a couple of lines and/or to introduce an helper function, but you would have the benefit of having a more explicit metaclass, with a simpler hierarchy (see the appendix for an alternative solution). > Maybe you could help me understand this by giving a fully executable > Python snippet using __bases__[0] instead of the hypothetical > __base__? To the best of my knowledge __base__ is a valid class attribute, it denotes the "right" class to use as base. Usually it is the same as bases[0], but there is at least one case when it is different, when composing old style and new style classes: >>> class OldStyle: pass >>> class NewStyle(object): pass >>> class New(OldStyle, NewStyle): pass >>> New.__bases__[0] <class __main__.OldStyle at 0x777060> >>> New.__base__ <class '__main__.NewStyle'> Appendix: how to reimplement cooperation in a single-inheritance world ---------------------------------------------------------------------------- Quoting Raymond: "To achieve substantially the same functionality, you would likely have to re-invent much of what super() does for us automatically, and you would still be imposing constraits on the composed classes that are substantially the same as what you have with inheritance." Raymond of course is right, but I am arguing that one does not really need to re-invent cooperation because the use case for cooperation are exceedingly rare. Still, if one really wants to reimplement cooperation, here is my take at the challenge: $ cat cooperative_mixins.py "Implements cooperative mixins using multiple-inheritance only" ## everything in three lines def include_mixin(mixin, cls): # could be extended to use more mixins # traits as in Squeak take the precedence over the base class dic = vars(mixin).copy() # could be extended to walk the ancestors dic['_%s__super' % mixin.__name__] = cls return type(mixin.__name__ + cls.__name__, (cls,), dic) ## examples: class FrameworkMeta(type): # example metaclass def __new__(mcl, name, bases, dic): print "Adding framework features to %s" % name return type.__new__(mcl, name, bases, dic) class DebugMeta(type): # mixin metaclass def __new__(mcl, name, bases, dic): print "Adding debugging features to %s" % name return mcl.__super.__new__(mcl, name, bases, dic) class RemotableMeta(type): # another mixin metaclass def __new__(mcl, name, bases, dic): print "Adding remoting features to %s" % name return mcl.__super.__new__(mcl, name, bases, dic) class FrameworkClass(object): __metaclass__ = FrameworkMeta DebugFrameworkMeta = include_mixin(DebugMeta, FrameworkMeta) print '**************** creating DebugFrameworkClass' class DebugFrameworkClass(FrameworkClass): __metaclass__ = DebugFrameworkMeta RemotableDebugFrameworkMeta = include_mixin( RemotableMeta, DebugFrameworkMeta) print '**************** creating RemotableDebugFrameworkClass' class RemotableDebugFrameworkClass(FrameworkClass): __metaclass__ = RemotableDebugFrameworkMeta _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com