In Python can one implement mixin behavior without using inheritance?

前端 未结 8 1637
醉梦人生
醉梦人生 2021-02-06 13:10

Is there a reasonable way in Python to implement mixin behavior similar to that found in Ruby -- that is, without using inheritance?

class Mixin(object):
    def         


        
8条回答
  •  广开言路
    2021-02-06 13:39

    This one is based on the way it's done in ruby as explained by Jörg W Mittag. All of the wall of code after if __name__=='__main__' is test/demo code. There's actually only 13 lines of real code to it.

    import inspect
    
    def add_mixins(*mixins):
        Dummy = type('Dummy', mixins, {})
        d = {}
    
        # Now get all the class attributes. Use reversed so that conflicts
        # are resolved with the proper priority. This rules out the possibility
        # of the mixins calling methods from their base classes that get overridden
        # using super but is necessary for the subclass check to fail. If that wasn't a
        # requirement, we would just use Dummy above (or use MI directly and
        # forget all the metaclass stuff).
    
        for base in reversed(inspect.getmro(Dummy)):
            d.update(base.__dict__)
    
        # Create the mixin class. This should be equivalent to creating the
        # anonymous class in Ruby.
        Mixin = type('Mixin', (object,), d)
    
        class WithMixins(type):
            def __new__(meta, classname, bases, classdict):
                # The check below prevents an inheritance cycle from forming which
                # leads to a TypeError when trying to inherit from the resulting
                # class.
                if not any(issubclass(base, Mixin) for base in bases):
                    # This should be the the equivalent of setting the superclass 
                    # pointers in Ruby.
                    bases = (Mixin,) + bases
                return super(WithMixins, meta).__new__(meta, classname, bases,
                                                       classdict)
    
        return WithMixins 
    
    
    if __name__ == '__main__':
    
        class Mixin1(object):
            def b(self): print "b()"
            def c(self): print "c()"
    
        class Mixin2(object):
            def d(self): print "d()"
            def e(self): print "e()"
    
        class Mixin3Base(object):
            def f(self): print "f()"
    
        class Mixin3(Mixin3Base): pass
    
        class Foo(object):
            __metaclass__ = add_mixins(Mixin1, Mixin2, Mixin3)
    
            def a(self): print "a()"
    
        class Bar(Foo):
            def f(self): print "Bar.f()"
    
        def test_class(cls):
            print "Testing {0}".format(cls.__name__)
            f = cls()
            f.a()
            f.b()
            f.c()
            f.d()
            f.e()
            f.f()
            print (issubclass(cls, Mixin1) or 
                   issubclass(cls, Mixin2) or
                   issubclass(cls, Mixin3))
    
        test_class(Foo)
        test_class(Bar)
    

提交回复
热议问题