Search code examples
pythondecoratorsuperclass

Python: can I use a class-level decorator to add a mixin to the decorated class?


I'd like to have a decorator that, among other stuff, adds a mixin to the class it's decorating. (I recognize that this may be a Really Bad Idea but bear with me.) The following almost works:

def add_mixin(cls):
   class inner(cls, NewMixin):
      pass
   return inner

Now if I do:

@add_mixin
class foo:
   ...bunch o' stuff...

class foo seems to work just fine, with NewMixin mixed in. (Maybe this scheme wouldn't exactly preserve the MRO of foo in the face of other superclasses but I don't think I care about that.)

The only problem I've found is that at this point foo.__name__ is "inner" and I'd like it to be "foo"! I can work around this by adding inner.__name__ = cls.__name__ in the definition of add_mixin and that seems to cover all the bases (as it were).

Question: Is there a better way to do this? Are there other lurking pitfalls here that I'm not seeing?

Thanks for any help.


Solution

  • Edit: The question was edited to mention this approach while I was writing the answer.

    You can do:

    def add_mixin(cls):
       class inner(cls, NewMixin):
          pass
       inner.__name__ = cls.__name__
       return inner
    

    and then:

    @add_mixin
    class foo:
       pass
    
    @add_mixin
    class bar:
       pass
    
    f = foo
    print(f.__name__)
    b = bar
    print(b.__name__)
    print(f.__name__)
    

    gives

    foo
    bar
    foo
    

    (Printing foo a second time after referencing bar to demonstrate that __name__ isn't overwritten.)

    In terms of pitfalls, that I'm not sure about.