Search code examples
pythonrubyinheritancemixins

In Python can one implement mixin behavior without using inheritance?


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 b(self): print "b()"
    def c(self): print "c()"

class Foo(object):
    # Somehow mix in the behavior of the Mixin class,
    # so that all of the methods below will run and
    # the issubclass() test will be False.

    def a(self): print "a()"

f = Foo()
f.a()
f.b()
f.c()
print issubclass(Foo, Mixin)

I had a vague idea to do this with a class decorator, but my attempts led to confusion. Most of my searches on the topic have led in the direction of using inheritance (or in more complex scenarios, multiple inheritance) to achieve mixin behavior.


Solution

  • def mixer(*args):
        """Decorator for mixing mixins"""
        def inner(cls):
            for a,k in ((a,k) for a in args for k,v in vars(a).items() if callable(v)):
                setattr(cls, k, getattr(a, k).im_func)
            return cls
        return inner
    
    class Mixin(object):
        def b(self): print "b()"
        def c(self): print "c()"
    
    class Mixin2(object):
        def d(self): print "d()"
        def e(self): print "e()"
    
    
    @mixer(Mixin, Mixin2)
    class Foo(object):
        # Somehow mix in the behavior of the Mixin class,
        # so that all of the methods below will run and
        # the issubclass() test will be False.
    
        def a(self): print "a()"
    
    f = Foo()
    f.a()
    f.b()
    f.c()
    f.d()
    f.e()
    print issubclass(Foo, Mixin)
    

    output:

    a()
    b()
    c()
    d()
    e()
    False